Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
RTClib.cpp@0:19609c3ba612, 2019-12-19 (annotated)
- Committer:
- ale87jan
- Date:
- Thu Dec 19 12:57:00 2019 +0000
- Revision:
- 0:19609c3ba612
DS3231 based on RTClib from Adafruit
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| ale87jan | 0:19609c3ba612 | 1 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 2 | /*! |
| ale87jan | 0:19609c3ba612 | 3 | @file RTClib.cpp |
| ale87jan | 0:19609c3ba612 | 4 | |
| ale87jan | 0:19609c3ba612 | 5 | @mainpage Adafruit RTClib |
| ale87jan | 0:19609c3ba612 | 6 | |
| ale87jan | 0:19609c3ba612 | 7 | @section intro Introduction |
| ale87jan | 0:19609c3ba612 | 8 | |
| ale87jan | 0:19609c3ba612 | 9 | This is a fork of JeeLab's fantastic real time clock library for Arduino. |
| ale87jan | 0:19609c3ba612 | 10 | |
| ale87jan | 0:19609c3ba612 | 11 | For details on using this library with an RTC module like the DS1307, PCF8523, or DS3231, |
| ale87jan | 0:19609c3ba612 | 12 | see the guide at: https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview |
| ale87jan | 0:19609c3ba612 | 13 | |
| ale87jan | 0:19609c3ba612 | 14 | Adafruit invests time and resources providing this open source code, |
| ale87jan | 0:19609c3ba612 | 15 | please support Adafruit and open-source hardware by purchasing |
| ale87jan | 0:19609c3ba612 | 16 | products from Adafruit! |
| ale87jan | 0:19609c3ba612 | 17 | |
| ale87jan | 0:19609c3ba612 | 18 | @section classes Available classes |
| ale87jan | 0:19609c3ba612 | 19 | |
| ale87jan | 0:19609c3ba612 | 20 | This library provides the following classes: |
| ale87jan | 0:19609c3ba612 | 21 | |
| ale87jan | 0:19609c3ba612 | 22 | - Classes for manipulating dates, times and durations: |
| ale87jan | 0:19609c3ba612 | 23 | - DateTime represents a specific point in time; this is the data |
| ale87jan | 0:19609c3ba612 | 24 | type used for setting and reading the supported RTCs |
| ale87jan | 0:19609c3ba612 | 25 | - TimeSpan represents the length of a time interval |
| ale87jan | 0:19609c3ba612 | 26 | - Interfacing specific RTC chips: |
| ale87jan | 0:19609c3ba612 | 27 | - RTC_DS1307 |
| ale87jan | 0:19609c3ba612 | 28 | - RTC_DS3231 |
| ale87jan | 0:19609c3ba612 | 29 | - RTC_PCF8523 |
| ale87jan | 0:19609c3ba612 | 30 | - RTC emulated in software; do not expect much accuracy out of these: |
| ale87jan | 0:19609c3ba612 | 31 | - RTC_Millis is based on `millis()` |
| ale87jan | 0:19609c3ba612 | 32 | - RTC_Micros is based on `micros()`; its drift rate can be tuned by |
| ale87jan | 0:19609c3ba612 | 33 | the user |
| ale87jan | 0:19609c3ba612 | 34 | |
| ale87jan | 0:19609c3ba612 | 35 | @section license License |
| ale87jan | 0:19609c3ba612 | 36 | |
| ale87jan | 0:19609c3ba612 | 37 | Original library by JeeLabs http://news.jeelabs.org/code/, released to the public domain. |
| ale87jan | 0:19609c3ba612 | 38 | |
| ale87jan | 0:19609c3ba612 | 39 | This version: MIT (see LICENSE) |
| ale87jan | 0:19609c3ba612 | 40 | */ |
| ale87jan | 0:19609c3ba612 | 41 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 42 | |
| ale87jan | 0:19609c3ba612 | 43 | #include "mbed.h" |
| ale87jan | 0:19609c3ba612 | 44 | #include <string> |
| ale87jan | 0:19609c3ba612 | 45 | //using namespace std; |
| ale87jan | 0:19609c3ba612 | 46 | #include "RTClib.h" |
| ale87jan | 0:19609c3ba612 | 47 | |
| ale87jan | 0:19609c3ba612 | 48 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 49 | /*! |
| ale87jan | 0:19609c3ba612 | 50 | @brief Read a uint8_t from an I2C register |
| ale87jan | 0:19609c3ba612 | 51 | @param addr I2C address |
| ale87jan | 0:19609c3ba612 | 52 | @param reg Register address |
| ale87jan | 0:19609c3ba612 | 53 | @return Register value |
| ale87jan | 0:19609c3ba612 | 54 | */ |
| ale87jan | 0:19609c3ba612 | 55 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 56 | uint8_t RTC_DS3231::read_i2c_register(uint8_t addr, uint8_t reg) |
| ale87jan | 0:19609c3ba612 | 57 | { |
| ale87jan | 0:19609c3ba612 | 58 | |
| ale87jan | 0:19609c3ba612 | 59 | char cmdData[1] = { (char)reg }; |
| ale87jan | 0:19609c3ba612 | 60 | char value; |
| ale87jan | 0:19609c3ba612 | 61 | |
| ale87jan | 0:19609c3ba612 | 62 | (*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData)); |
| ale87jan | 0:19609c3ba612 | 63 | |
| ale87jan | 0:19609c3ba612 | 64 | (*_i2c).read(DS3231_ADDRESS, &value, 1); |
| ale87jan | 0:19609c3ba612 | 65 | |
| ale87jan | 0:19609c3ba612 | 66 | return value; |
| ale87jan | 0:19609c3ba612 | 67 | } |
| ale87jan | 0:19609c3ba612 | 68 | |
| ale87jan | 0:19609c3ba612 | 69 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 70 | /*! |
| ale87jan | 0:19609c3ba612 | 71 | @brief Write a uint8_t to an I2C register |
| ale87jan | 0:19609c3ba612 | 72 | @param addr I2C address |
| ale87jan | 0:19609c3ba612 | 73 | @param reg Register address |
| ale87jan | 0:19609c3ba612 | 74 | @param val Value to write |
| ale87jan | 0:19609c3ba612 | 75 | */ |
| ale87jan | 0:19609c3ba612 | 76 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 77 | void RTC_DS3231::write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) |
| ale87jan | 0:19609c3ba612 | 78 | { |
| ale87jan | 0:19609c3ba612 | 79 | char cmdData[2] = { (char)reg, val }; |
| ale87jan | 0:19609c3ba612 | 80 | |
| ale87jan | 0:19609c3ba612 | 81 | (*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData)); |
| ale87jan | 0:19609c3ba612 | 82 | |
| ale87jan | 0:19609c3ba612 | 83 | } |
| ale87jan | 0:19609c3ba612 | 84 | |
| ale87jan | 0:19609c3ba612 | 85 | |
| ale87jan | 0:19609c3ba612 | 86 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 87 | // utility code, some of this could be exposed in the DateTime API if needed |
| ale87jan | 0:19609c3ba612 | 88 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 89 | |
| ale87jan | 0:19609c3ba612 | 90 | /** |
| ale87jan | 0:19609c3ba612 | 91 | Number of days in each month, from January to November. December is not |
| ale87jan | 0:19609c3ba612 | 92 | needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time |
| ale87jan | 0:19609c3ba612 | 93 | library. C.f. https://github.com/adafruit/RTClib/issues/114 |
| ale87jan | 0:19609c3ba612 | 94 | */ |
| ale87jan | 0:19609c3ba612 | 95 | const uint8_t daysInMonth [] = { 31,28,31,30,31,30,31,31,30,31,30 }; |
| ale87jan | 0:19609c3ba612 | 96 | |
| ale87jan | 0:19609c3ba612 | 97 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 98 | /*! |
| ale87jan | 0:19609c3ba612 | 99 | @brief Given a date, return number of days since 2000/01/01, valid for 2001..2099 |
| ale87jan | 0:19609c3ba612 | 100 | @param y Year |
| ale87jan | 0:19609c3ba612 | 101 | @param m Month |
| ale87jan | 0:19609c3ba612 | 102 | @param d Day |
| ale87jan | 0:19609c3ba612 | 103 | @return Number of days |
| ale87jan | 0:19609c3ba612 | 104 | */ |
| ale87jan | 0:19609c3ba612 | 105 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 106 | static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) |
| ale87jan | 0:19609c3ba612 | 107 | { |
| ale87jan | 0:19609c3ba612 | 108 | if (y >= 2000) |
| ale87jan | 0:19609c3ba612 | 109 | y -= 2000; |
| ale87jan | 0:19609c3ba612 | 110 | uint16_t days = d; |
| ale87jan | 0:19609c3ba612 | 111 | for (uint8_t i = 1; i < m; ++i) |
| ale87jan | 0:19609c3ba612 | 112 | days += daysInMonth [i - 1]; |
| ale87jan | 0:19609c3ba612 | 113 | if (m > 2 && y % 4 == 0) |
| ale87jan | 0:19609c3ba612 | 114 | ++days; |
| ale87jan | 0:19609c3ba612 | 115 | return days + 365 * y + (y + 3) / 4 - 1; |
| ale87jan | 0:19609c3ba612 | 116 | } |
| ale87jan | 0:19609c3ba612 | 117 | |
| ale87jan | 0:19609c3ba612 | 118 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 119 | /*! |
| ale87jan | 0:19609c3ba612 | 120 | @brief Given a number of days, hours, minutes, and seconds, return the total seconds |
| ale87jan | 0:19609c3ba612 | 121 | @param days Days |
| ale87jan | 0:19609c3ba612 | 122 | @param h Hours |
| ale87jan | 0:19609c3ba612 | 123 | @param m Minutes |
| ale87jan | 0:19609c3ba612 | 124 | @param s Seconds |
| ale87jan | 0:19609c3ba612 | 125 | @return Number of seconds total |
| ale87jan | 0:19609c3ba612 | 126 | */ |
| ale87jan | 0:19609c3ba612 | 127 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 128 | static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) |
| ale87jan | 0:19609c3ba612 | 129 | { |
| ale87jan | 0:19609c3ba612 | 130 | return ((days * 24L + h) * 60 + m) * 60 + s; |
| ale87jan | 0:19609c3ba612 | 131 | } |
| ale87jan | 0:19609c3ba612 | 132 | |
| ale87jan | 0:19609c3ba612 | 133 | |
| ale87jan | 0:19609c3ba612 | 134 | |
| ale87jan | 0:19609c3ba612 | 135 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 136 | /*! |
| ale87jan | 0:19609c3ba612 | 137 | @brief DateTime constructor from unixtime |
| ale87jan | 0:19609c3ba612 | 138 | @param t Initial time in seconds since Jan 1, 1970 (Unix time) |
| ale87jan | 0:19609c3ba612 | 139 | */ |
| ale87jan | 0:19609c3ba612 | 140 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 141 | DateTime::DateTime (uint32_t t) |
| ale87jan | 0:19609c3ba612 | 142 | { |
| ale87jan | 0:19609c3ba612 | 143 | t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970 |
| ale87jan | 0:19609c3ba612 | 144 | |
| ale87jan | 0:19609c3ba612 | 145 | ss = t % 60; |
| ale87jan | 0:19609c3ba612 | 146 | t /= 60; |
| ale87jan | 0:19609c3ba612 | 147 | mm = t % 60; |
| ale87jan | 0:19609c3ba612 | 148 | t /= 60; |
| ale87jan | 0:19609c3ba612 | 149 | hh = t % 24; |
| ale87jan | 0:19609c3ba612 | 150 | uint16_t days = t / 24; |
| ale87jan | 0:19609c3ba612 | 151 | uint8_t leap; |
| ale87jan | 0:19609c3ba612 | 152 | for (yOff = 0; ; ++yOff) { |
| ale87jan | 0:19609c3ba612 | 153 | leap = yOff % 4 == 0; |
| ale87jan | 0:19609c3ba612 | 154 | if (days < 365 + leap) |
| ale87jan | 0:19609c3ba612 | 155 | break; |
| ale87jan | 0:19609c3ba612 | 156 | days -= 365 + leap; |
| ale87jan | 0:19609c3ba612 | 157 | } |
| ale87jan | 0:19609c3ba612 | 158 | for (m = 1; m < 12; ++m) { |
| ale87jan | 0:19609c3ba612 | 159 | uint8_t daysPerMonth = daysInMonth [m - 1]; |
| ale87jan | 0:19609c3ba612 | 160 | if (leap && m == 2) |
| ale87jan | 0:19609c3ba612 | 161 | ++daysPerMonth; |
| ale87jan | 0:19609c3ba612 | 162 | if (days < daysPerMonth) |
| ale87jan | 0:19609c3ba612 | 163 | break; |
| ale87jan | 0:19609c3ba612 | 164 | days -= daysPerMonth; |
| ale87jan | 0:19609c3ba612 | 165 | } |
| ale87jan | 0:19609c3ba612 | 166 | d = days + 1; |
| ale87jan | 0:19609c3ba612 | 167 | } |
| ale87jan | 0:19609c3ba612 | 168 | |
| ale87jan | 0:19609c3ba612 | 169 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 170 | /*! |
| ale87jan | 0:19609c3ba612 | 171 | @brief DateTime constructor from Y-M-D H:M:S |
| ale87jan | 0:19609c3ba612 | 172 | @param year Year, 2 or 4 digits (year 2000 or higher) |
| ale87jan | 0:19609c3ba612 | 173 | @param month Month 1-12 |
| ale87jan | 0:19609c3ba612 | 174 | @param day Day 1-31 |
| ale87jan | 0:19609c3ba612 | 175 | @param hour 0-23 |
| ale87jan | 0:19609c3ba612 | 176 | @param min 0-59 |
| ale87jan | 0:19609c3ba612 | 177 | @param sec 0-59 |
| ale87jan | 0:19609c3ba612 | 178 | */ |
| ale87jan | 0:19609c3ba612 | 179 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 180 | DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) |
| ale87jan | 0:19609c3ba612 | 181 | { |
| ale87jan | 0:19609c3ba612 | 182 | if (year >= 2000) |
| ale87jan | 0:19609c3ba612 | 183 | year -= 2000; |
| ale87jan | 0:19609c3ba612 | 184 | yOff = year; |
| ale87jan | 0:19609c3ba612 | 185 | m = month; |
| ale87jan | 0:19609c3ba612 | 186 | d = day; |
| ale87jan | 0:19609c3ba612 | 187 | hh = hour; |
| ale87jan | 0:19609c3ba612 | 188 | mm = min; |
| ale87jan | 0:19609c3ba612 | 189 | ss = sec; |
| ale87jan | 0:19609c3ba612 | 190 | } |
| ale87jan | 0:19609c3ba612 | 191 | |
| ale87jan | 0:19609c3ba612 | 192 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 193 | /*! |
| ale87jan | 0:19609c3ba612 | 194 | @brief DateTime copy constructor using a member initializer list |
| ale87jan | 0:19609c3ba612 | 195 | @param copy DateTime object to copy |
| ale87jan | 0:19609c3ba612 | 196 | */ |
| ale87jan | 0:19609c3ba612 | 197 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 198 | DateTime::DateTime (const DateTime& copy): |
| ale87jan | 0:19609c3ba612 | 199 | yOff(copy.yOff), |
| ale87jan | 0:19609c3ba612 | 200 | m(copy.m), |
| ale87jan | 0:19609c3ba612 | 201 | d(copy.d), |
| ale87jan | 0:19609c3ba612 | 202 | hh(copy.hh), |
| ale87jan | 0:19609c3ba612 | 203 | mm(copy.mm), |
| ale87jan | 0:19609c3ba612 | 204 | ss(copy.ss) |
| ale87jan | 0:19609c3ba612 | 205 | {} |
| ale87jan | 0:19609c3ba612 | 206 | |
| ale87jan | 0:19609c3ba612 | 207 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 208 | /*! |
| ale87jan | 0:19609c3ba612 | 209 | @brief Convert a string containing two digits to uint8_t, e.g. "09" returns 9 |
| ale87jan | 0:19609c3ba612 | 210 | @param p Pointer to a string containing two digits |
| ale87jan | 0:19609c3ba612 | 211 | */ |
| ale87jan | 0:19609c3ba612 | 212 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 213 | static uint8_t conv2d(const char* p) |
| ale87jan | 0:19609c3ba612 | 214 | { |
| ale87jan | 0:19609c3ba612 | 215 | uint8_t v = 0; |
| ale87jan | 0:19609c3ba612 | 216 | if ('0' <= *p && *p <= '9') |
| ale87jan | 0:19609c3ba612 | 217 | v = *p - '0'; |
| ale87jan | 0:19609c3ba612 | 218 | return 10 * v + *++p - '0'; |
| ale87jan | 0:19609c3ba612 | 219 | } |
| ale87jan | 0:19609c3ba612 | 220 | |
| ale87jan | 0:19609c3ba612 | 221 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 222 | /*! |
| ale87jan | 0:19609c3ba612 | 223 | @brief A convenient constructor for using "the compiler's time": |
| ale87jan | 0:19609c3ba612 | 224 | DateTime now (__DATE__, __TIME__); |
| ale87jan | 0:19609c3ba612 | 225 | NOTE: using F() would further reduce the RAM footprint, see below. |
| ale87jan | 0:19609c3ba612 | 226 | @param date Date string, e.g. "Dec 26 2009" |
| ale87jan | 0:19609c3ba612 | 227 | @param time Time string, e.g. "12:34:56" |
| ale87jan | 0:19609c3ba612 | 228 | */ |
| ale87jan | 0:19609c3ba612 | 229 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 230 | DateTime::DateTime (const char* date, const char* time) |
| ale87jan | 0:19609c3ba612 | 231 | { |
| ale87jan | 0:19609c3ba612 | 232 | // sample input: date = "Dec 26 2009", time = "12:34:56" |
| ale87jan | 0:19609c3ba612 | 233 | yOff = conv2d(date + 9); |
| ale87jan | 0:19609c3ba612 | 234 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec |
| ale87jan | 0:19609c3ba612 | 235 | switch (date[0]) { |
| ale87jan | 0:19609c3ba612 | 236 | case 'J': |
| ale87jan | 0:19609c3ba612 | 237 | m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7); |
| ale87jan | 0:19609c3ba612 | 238 | break; |
| ale87jan | 0:19609c3ba612 | 239 | case 'F': |
| ale87jan | 0:19609c3ba612 | 240 | m = 2; |
| ale87jan | 0:19609c3ba612 | 241 | break; |
| ale87jan | 0:19609c3ba612 | 242 | case 'A': |
| ale87jan | 0:19609c3ba612 | 243 | m = date[2] == 'r' ? 4 : 8; |
| ale87jan | 0:19609c3ba612 | 244 | break; |
| ale87jan | 0:19609c3ba612 | 245 | case 'M': |
| ale87jan | 0:19609c3ba612 | 246 | m = date[2] == 'r' ? 3 : 5; |
| ale87jan | 0:19609c3ba612 | 247 | break; |
| ale87jan | 0:19609c3ba612 | 248 | case 'S': |
| ale87jan | 0:19609c3ba612 | 249 | m = 9; |
| ale87jan | 0:19609c3ba612 | 250 | break; |
| ale87jan | 0:19609c3ba612 | 251 | case 'O': |
| ale87jan | 0:19609c3ba612 | 252 | m = 10; |
| ale87jan | 0:19609c3ba612 | 253 | break; |
| ale87jan | 0:19609c3ba612 | 254 | case 'N': |
| ale87jan | 0:19609c3ba612 | 255 | m = 11; |
| ale87jan | 0:19609c3ba612 | 256 | break; |
| ale87jan | 0:19609c3ba612 | 257 | case 'D': |
| ale87jan | 0:19609c3ba612 | 258 | m = 12; |
| ale87jan | 0:19609c3ba612 | 259 | break; |
| ale87jan | 0:19609c3ba612 | 260 | } |
| ale87jan | 0:19609c3ba612 | 261 | d = conv2d(date + 4); |
| ale87jan | 0:19609c3ba612 | 262 | hh = conv2d(time); |
| ale87jan | 0:19609c3ba612 | 263 | mm = conv2d(time + 3); |
| ale87jan | 0:19609c3ba612 | 264 | ss = conv2d(time + 6); |
| ale87jan | 0:19609c3ba612 | 265 | } |
| ale87jan | 0:19609c3ba612 | 266 | |
| ale87jan | 0:19609c3ba612 | 267 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 268 | /*! |
| ale87jan | 0:19609c3ba612 | 269 | @brief A convenient constructor for using "the compiler's time": |
| ale87jan | 0:19609c3ba612 | 270 | This version will save RAM by using PROGMEM to store it by using the F macro. |
| ale87jan | 0:19609c3ba612 | 271 | DateTime now (F(__DATE__), F(__TIME__)); |
| ale87jan | 0:19609c3ba612 | 272 | @param date Date string, e.g. "Dec 26 2009" |
| ale87jan | 0:19609c3ba612 | 273 | @param time Time string, e.g. "12:34:56" |
| ale87jan | 0:19609c3ba612 | 274 | */ |
| ale87jan | 0:19609c3ba612 | 275 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 276 | /*DateTime::DateTime (const __FlashstringHelper* date, const __FlashstringHelper* time) { |
| ale87jan | 0:19609c3ba612 | 277 | // sample input: date = "Dec 26 2009", time = "12:34:56" |
| ale87jan | 0:19609c3ba612 | 278 | char buff[11]; |
| ale87jan | 0:19609c3ba612 | 279 | memcpy_P(buff, date, 11); |
| ale87jan | 0:19609c3ba612 | 280 | yOff = conv2d(buff + 9); |
| ale87jan | 0:19609c3ba612 | 281 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec |
| ale87jan | 0:19609c3ba612 | 282 | switch (buff[0]) { |
| ale87jan | 0:19609c3ba612 | 283 | case 'J': m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7); break; |
| ale87jan | 0:19609c3ba612 | 284 | case 'F': m = 2; break; |
| ale87jan | 0:19609c3ba612 | 285 | case 'A': m = buff[2] == 'r' ? 4 : 8; break; |
| ale87jan | 0:19609c3ba612 | 286 | case 'M': m = buff[2] == 'r' ? 3 : 5; break; |
| ale87jan | 0:19609c3ba612 | 287 | case 'S': m = 9; break; |
| ale87jan | 0:19609c3ba612 | 288 | case 'O': m = 10; break; |
| ale87jan | 0:19609c3ba612 | 289 | case 'N': m = 11; break; |
| ale87jan | 0:19609c3ba612 | 290 | case 'D': m = 12; break; |
| ale87jan | 0:19609c3ba612 | 291 | } |
| ale87jan | 0:19609c3ba612 | 292 | d = conv2d(buff + 4); |
| ale87jan | 0:19609c3ba612 | 293 | memcpy_P(buff, time, 8); |
| ale87jan | 0:19609c3ba612 | 294 | hh = conv2d(buff); |
| ale87jan | 0:19609c3ba612 | 295 | mm = conv2d(buff + 3); |
| ale87jan | 0:19609c3ba612 | 296 | ss = conv2d(buff + 6); |
| ale87jan | 0:19609c3ba612 | 297 | }*/ |
| ale87jan | 0:19609c3ba612 | 298 | |
| ale87jan | 0:19609c3ba612 | 299 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 300 | /*! |
| ale87jan | 0:19609c3ba612 | 301 | @brief Return DateTime in based on user defined format. |
| ale87jan | 0:19609c3ba612 | 302 | @param buffer: array of char for holding the format description and the formatted DateTime. |
| ale87jan | 0:19609c3ba612 | 303 | Before calling this method, the buffer should be initialized by the user with |
| ale87jan | 0:19609c3ba612 | 304 | a format string, e.g. "YYYY-MM-DD hh:mm:ss". The method will overwrite |
| ale87jan | 0:19609c3ba612 | 305 | the buffer with the formatted date and/or time. |
| ale87jan | 0:19609c3ba612 | 306 | @return a pointer to the provided buffer. This is returned for convenience, |
| ale87jan | 0:19609c3ba612 | 307 | in order to enable idioms such as Serial.println(now.tostring(buffer)); |
| ale87jan | 0:19609c3ba612 | 308 | */ |
| ale87jan | 0:19609c3ba612 | 309 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 310 | |
| ale87jan | 0:19609c3ba612 | 311 | char* DateTime::tostring(char* buffer) |
| ale87jan | 0:19609c3ba612 | 312 | { |
| ale87jan | 0:19609c3ba612 | 313 | for(int i=0; i<strlen(buffer)-1; i++) { |
| ale87jan | 0:19609c3ba612 | 314 | if(buffer[i] == 'h' && buffer[i+1] == 'h') { |
| ale87jan | 0:19609c3ba612 | 315 | buffer[i] = '0'+hh/10; |
| ale87jan | 0:19609c3ba612 | 316 | buffer[i+1] = '0'+hh%10; |
| ale87jan | 0:19609c3ba612 | 317 | } |
| ale87jan | 0:19609c3ba612 | 318 | if(buffer[i] == 'm' && buffer[i+1] == 'm') { |
| ale87jan | 0:19609c3ba612 | 319 | buffer[i] = '0'+mm/10; |
| ale87jan | 0:19609c3ba612 | 320 | buffer[i+1] = '0'+mm%10; |
| ale87jan | 0:19609c3ba612 | 321 | } |
| ale87jan | 0:19609c3ba612 | 322 | if(buffer[i] == 's' && buffer[i+1] == 's') { |
| ale87jan | 0:19609c3ba612 | 323 | buffer[i] = '0'+ss/10; |
| ale87jan | 0:19609c3ba612 | 324 | buffer[i+1] = '0'+ss%10; |
| ale87jan | 0:19609c3ba612 | 325 | } |
| ale87jan | 0:19609c3ba612 | 326 | if(buffer[i] == 'D' && buffer[i+1] =='D' && buffer[i+2] =='D') { |
| ale87jan | 0:19609c3ba612 | 327 | static const char day_names[] = "SunMonTueWedThuFriSat"; |
| ale87jan | 0:19609c3ba612 | 328 | const uint8_t p = 3*dayOfTheWeek(); |
| ale87jan | 0:19609c3ba612 | 329 | buffer[i] = day_names[p]; |
| ale87jan | 0:19609c3ba612 | 330 | buffer[i+1] = day_names[p+1]; |
| ale87jan | 0:19609c3ba612 | 331 | buffer[i+2] = day_names[p+2]; |
| ale87jan | 0:19609c3ba612 | 332 | } else if(buffer[i] == 'D' && buffer[i+1] == 'D') { |
| ale87jan | 0:19609c3ba612 | 333 | buffer[i] = '0'+d/10; |
| ale87jan | 0:19609c3ba612 | 334 | buffer[i+1] = '0'+d%10; |
| ale87jan | 0:19609c3ba612 | 335 | } |
| ale87jan | 0:19609c3ba612 | 336 | if(buffer[i] == 'M' && buffer[i+1] =='M' && buffer[i+2] =='M') { |
| ale87jan | 0:19609c3ba612 | 337 | static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; |
| ale87jan | 0:19609c3ba612 | 338 | const uint8_t p = 3*(m-1); |
| ale87jan | 0:19609c3ba612 | 339 | buffer[i] = month_names[p]; |
| ale87jan | 0:19609c3ba612 | 340 | buffer[i+1] = month_names[p+1]; |
| ale87jan | 0:19609c3ba612 | 341 | buffer[i+2] = month_names[p+2]; |
| ale87jan | 0:19609c3ba612 | 342 | } else if(buffer[i] == 'M' && buffer[i+1] == 'M') { |
| ale87jan | 0:19609c3ba612 | 343 | buffer[i] = '0'+m/10; |
| ale87jan | 0:19609c3ba612 | 344 | buffer[i+1] = '0'+m%10; |
| ale87jan | 0:19609c3ba612 | 345 | } |
| ale87jan | 0:19609c3ba612 | 346 | if(buffer[i] == 'Y'&& buffer[i+1] == 'Y'&& buffer[i+2] == 'Y'&& buffer[i+3] == 'Y') { |
| ale87jan | 0:19609c3ba612 | 347 | buffer[i] = '2'; |
| ale87jan | 0:19609c3ba612 | 348 | buffer[i+1] = '0'; |
| ale87jan | 0:19609c3ba612 | 349 | buffer[i+2] = '0'+(yOff/10)%10; |
| ale87jan | 0:19609c3ba612 | 350 | buffer[i+3] = '0'+yOff%10; |
| ale87jan | 0:19609c3ba612 | 351 | } else if(buffer[i] == 'Y'&& buffer[i+1] == 'Y') { |
| ale87jan | 0:19609c3ba612 | 352 | buffer[i] = '0'+(yOff/10)%10; |
| ale87jan | 0:19609c3ba612 | 353 | buffer[i+1] = '0'+yOff%10; |
| ale87jan | 0:19609c3ba612 | 354 | } |
| ale87jan | 0:19609c3ba612 | 355 | |
| ale87jan | 0:19609c3ba612 | 356 | } |
| ale87jan | 0:19609c3ba612 | 357 | return buffer; |
| ale87jan | 0:19609c3ba612 | 358 | } |
| ale87jan | 0:19609c3ba612 | 359 | |
| ale87jan | 0:19609c3ba612 | 360 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 361 | /*! |
| ale87jan | 0:19609c3ba612 | 362 | @brief Return the day of the week for this object, from 0-6. |
| ale87jan | 0:19609c3ba612 | 363 | @return Day of week 0-6 starting with Sunday, e.g. Sunday = 0, Saturday = 6 |
| ale87jan | 0:19609c3ba612 | 364 | */ |
| ale87jan | 0:19609c3ba612 | 365 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 366 | uint8_t DateTime::dayOfTheWeek() const |
| ale87jan | 0:19609c3ba612 | 367 | { |
| ale87jan | 0:19609c3ba612 | 368 | uint16_t day = date2days(yOff, m, d); |
| ale87jan | 0:19609c3ba612 | 369 | return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6 |
| ale87jan | 0:19609c3ba612 | 370 | } |
| ale87jan | 0:19609c3ba612 | 371 | |
| ale87jan | 0:19609c3ba612 | 372 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 373 | /*! |
| ale87jan | 0:19609c3ba612 | 374 | @brief Return unix time, seconds since Jan 1, 1970. |
| ale87jan | 0:19609c3ba612 | 375 | @return Number of seconds since Jan 1, 1970 |
| ale87jan | 0:19609c3ba612 | 376 | */ |
| ale87jan | 0:19609c3ba612 | 377 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 378 | uint32_t DateTime::unixtime(void) const |
| ale87jan | 0:19609c3ba612 | 379 | { |
| ale87jan | 0:19609c3ba612 | 380 | uint32_t t; |
| ale87jan | 0:19609c3ba612 | 381 | uint16_t days = date2days(yOff, m, d); |
| ale87jan | 0:19609c3ba612 | 382 | t = time2long(days, hh, mm, ss); |
| ale87jan | 0:19609c3ba612 | 383 | t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000 |
| ale87jan | 0:19609c3ba612 | 384 | |
| ale87jan | 0:19609c3ba612 | 385 | return t; |
| ale87jan | 0:19609c3ba612 | 386 | } |
| ale87jan | 0:19609c3ba612 | 387 | |
| ale87jan | 0:19609c3ba612 | 388 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 389 | /*! |
| ale87jan | 0:19609c3ba612 | 390 | @brief Convert the DateTime to seconds |
| ale87jan | 0:19609c3ba612 | 391 | @return The object as seconds since 2000-01-01 |
| ale87jan | 0:19609c3ba612 | 392 | */ |
| ale87jan | 0:19609c3ba612 | 393 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 394 | long DateTime::secondstime(void) const |
| ale87jan | 0:19609c3ba612 | 395 | { |
| ale87jan | 0:19609c3ba612 | 396 | long t; |
| ale87jan | 0:19609c3ba612 | 397 | uint16_t days = date2days(yOff, m, d); |
| ale87jan | 0:19609c3ba612 | 398 | t = time2long(days, hh, mm, ss); |
| ale87jan | 0:19609c3ba612 | 399 | return t; |
| ale87jan | 0:19609c3ba612 | 400 | } |
| ale87jan | 0:19609c3ba612 | 401 | |
| ale87jan | 0:19609c3ba612 | 402 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 403 | /*! |
| ale87jan | 0:19609c3ba612 | 404 | @brief Add a TimeSpan to the DateTime object |
| ale87jan | 0:19609c3ba612 | 405 | @param span TimeSpan object |
| ale87jan | 0:19609c3ba612 | 406 | @return new DateTime object with span added to it |
| ale87jan | 0:19609c3ba612 | 407 | */ |
| ale87jan | 0:19609c3ba612 | 408 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 409 | DateTime DateTime::operator+(const TimeSpan& span) |
| ale87jan | 0:19609c3ba612 | 410 | { |
| ale87jan | 0:19609c3ba612 | 411 | return DateTime(unixtime()+span.totalseconds()); |
| ale87jan | 0:19609c3ba612 | 412 | } |
| ale87jan | 0:19609c3ba612 | 413 | |
| ale87jan | 0:19609c3ba612 | 414 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 415 | /*! |
| ale87jan | 0:19609c3ba612 | 416 | @brief Subtract a TimeSpan from the DateTime object |
| ale87jan | 0:19609c3ba612 | 417 | @param span TimeSpan object |
| ale87jan | 0:19609c3ba612 | 418 | @return new DateTime object with span subtracted from it |
| ale87jan | 0:19609c3ba612 | 419 | */ |
| ale87jan | 0:19609c3ba612 | 420 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 421 | DateTime DateTime::operator-(const TimeSpan& span) |
| ale87jan | 0:19609c3ba612 | 422 | { |
| ale87jan | 0:19609c3ba612 | 423 | return DateTime(unixtime()-span.totalseconds()); |
| ale87jan | 0:19609c3ba612 | 424 | } |
| ale87jan | 0:19609c3ba612 | 425 | |
| ale87jan | 0:19609c3ba612 | 426 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 427 | /*! |
| ale87jan | 0:19609c3ba612 | 428 | @brief Subtract one DateTime from another |
| ale87jan | 0:19609c3ba612 | 429 | @param right The DateTime object to subtract from self (the left object) |
| ale87jan | 0:19609c3ba612 | 430 | @return TimeSpan of the difference between DateTimes |
| ale87jan | 0:19609c3ba612 | 431 | */ |
| ale87jan | 0:19609c3ba612 | 432 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 433 | TimeSpan DateTime::operator-(const DateTime& right) |
| ale87jan | 0:19609c3ba612 | 434 | { |
| ale87jan | 0:19609c3ba612 | 435 | return TimeSpan(unixtime()-right.unixtime()); |
| ale87jan | 0:19609c3ba612 | 436 | } |
| ale87jan | 0:19609c3ba612 | 437 | |
| ale87jan | 0:19609c3ba612 | 438 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 439 | /*! |
| ale87jan | 0:19609c3ba612 | 440 | @brief Is one DateTime object less than (older) than the other? |
| ale87jan | 0:19609c3ba612 | 441 | @param right Comparison DateTime object |
| ale87jan | 0:19609c3ba612 | 442 | @return True if the left object is older than the right object |
| ale87jan | 0:19609c3ba612 | 443 | */ |
| ale87jan | 0:19609c3ba612 | 444 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 445 | bool DateTime::operator<(const DateTime& right) const |
| ale87jan | 0:19609c3ba612 | 446 | { |
| ale87jan | 0:19609c3ba612 | 447 | return unixtime() < right.unixtime(); |
| ale87jan | 0:19609c3ba612 | 448 | } |
| ale87jan | 0:19609c3ba612 | 449 | |
| ale87jan | 0:19609c3ba612 | 450 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 451 | /*! |
| ale87jan | 0:19609c3ba612 | 452 | @brief Is one DateTime object equal to the other? |
| ale87jan | 0:19609c3ba612 | 453 | @param right Comparison DateTime object |
| ale87jan | 0:19609c3ba612 | 454 | @return True if both DateTime objects are the same |
| ale87jan | 0:19609c3ba612 | 455 | */ |
| ale87jan | 0:19609c3ba612 | 456 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 457 | bool DateTime::operator==(const DateTime& right) const |
| ale87jan | 0:19609c3ba612 | 458 | { |
| ale87jan | 0:19609c3ba612 | 459 | return unixtime() == right.unixtime(); |
| ale87jan | 0:19609c3ba612 | 460 | } |
| ale87jan | 0:19609c3ba612 | 461 | |
| ale87jan | 0:19609c3ba612 | 462 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 463 | /*! |
| ale87jan | 0:19609c3ba612 | 464 | @brief ISO 8601 Timestamp |
| ale87jan | 0:19609c3ba612 | 465 | @param opt Format of the timestamp |
| ale87jan | 0:19609c3ba612 | 466 | @return Timestamp string, e.g. "2000-01-01T12:34:56" |
| ale87jan | 0:19609c3ba612 | 467 | */ |
| ale87jan | 0:19609c3ba612 | 468 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 469 | string DateTime::timestamp(timestampOpt opt) |
| ale87jan | 0:19609c3ba612 | 470 | { |
| ale87jan | 0:19609c3ba612 | 471 | char buffer[20]; |
| ale87jan | 0:19609c3ba612 | 472 | |
| ale87jan | 0:19609c3ba612 | 473 | //Generate timestamp according to opt |
| ale87jan | 0:19609c3ba612 | 474 | switch(opt) { |
| ale87jan | 0:19609c3ba612 | 475 | case TIMESTAMP_TIME: |
| ale87jan | 0:19609c3ba612 | 476 | //Only time |
| ale87jan | 0:19609c3ba612 | 477 | sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss); |
| ale87jan | 0:19609c3ba612 | 478 | break; |
| ale87jan | 0:19609c3ba612 | 479 | case TIMESTAMP_DATE: |
| ale87jan | 0:19609c3ba612 | 480 | //Only date |
| ale87jan | 0:19609c3ba612 | 481 | sprintf(buffer, "%d-%02d-%02d", 2000+yOff, m, d); |
| ale87jan | 0:19609c3ba612 | 482 | break; |
| ale87jan | 0:19609c3ba612 | 483 | default: |
| ale87jan | 0:19609c3ba612 | 484 | //Full |
| ale87jan | 0:19609c3ba612 | 485 | sprintf(buffer, "%d-%02d-%02dT%02d:%02d:%02d", 2000+yOff, m, d, hh, mm, ss); |
| ale87jan | 0:19609c3ba612 | 486 | } |
| ale87jan | 0:19609c3ba612 | 487 | return string(buffer); |
| ale87jan | 0:19609c3ba612 | 488 | } |
| ale87jan | 0:19609c3ba612 | 489 | |
| ale87jan | 0:19609c3ba612 | 490 | |
| ale87jan | 0:19609c3ba612 | 491 | |
| ale87jan | 0:19609c3ba612 | 492 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 493 | /*! |
| ale87jan | 0:19609c3ba612 | 494 | @brief Create a new TimeSpan object in seconds |
| ale87jan | 0:19609c3ba612 | 495 | @param seconds Number of seconds |
| ale87jan | 0:19609c3ba612 | 496 | */ |
| ale87jan | 0:19609c3ba612 | 497 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 498 | TimeSpan::TimeSpan (int32_t seconds): |
| ale87jan | 0:19609c3ba612 | 499 | _seconds(seconds) |
| ale87jan | 0:19609c3ba612 | 500 | {} |
| ale87jan | 0:19609c3ba612 | 501 | |
| ale87jan | 0:19609c3ba612 | 502 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 503 | /*! |
| ale87jan | 0:19609c3ba612 | 504 | @brief Create a new TimeSpan object using a number of days/hours/minutes/seconds |
| ale87jan | 0:19609c3ba612 | 505 | e.g. Make a TimeSpan of 3 hours and 45 minutes: new TimeSpan(0, 3, 45, 0); |
| ale87jan | 0:19609c3ba612 | 506 | @param days Number of days |
| ale87jan | 0:19609c3ba612 | 507 | @param hours Number of hours |
| ale87jan | 0:19609c3ba612 | 508 | @param minutes Number of minutes |
| ale87jan | 0:19609c3ba612 | 509 | @param seconds Number of seconds |
| ale87jan | 0:19609c3ba612 | 510 | */ |
| ale87jan | 0:19609c3ba612 | 511 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 512 | TimeSpan::TimeSpan (int16_t days, int8_t hours, int8_t minutes, int8_t seconds): |
| ale87jan | 0:19609c3ba612 | 513 | _seconds((int32_t)days*86400L + (int32_t)hours*3600 + (int32_t)minutes*60 + seconds) |
| ale87jan | 0:19609c3ba612 | 514 | {} |
| ale87jan | 0:19609c3ba612 | 515 | |
| ale87jan | 0:19609c3ba612 | 516 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 517 | /*! |
| ale87jan | 0:19609c3ba612 | 518 | @brief Copy constructor, make a new TimeSpan using an existing one |
| ale87jan | 0:19609c3ba612 | 519 | @param copy The TimeSpan to copy |
| ale87jan | 0:19609c3ba612 | 520 | */ |
| ale87jan | 0:19609c3ba612 | 521 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 522 | TimeSpan::TimeSpan (const TimeSpan& copy): |
| ale87jan | 0:19609c3ba612 | 523 | _seconds(copy._seconds) |
| ale87jan | 0:19609c3ba612 | 524 | {} |
| ale87jan | 0:19609c3ba612 | 525 | |
| ale87jan | 0:19609c3ba612 | 526 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 527 | /*! |
| ale87jan | 0:19609c3ba612 | 528 | @brief Add two TimeSpans |
| ale87jan | 0:19609c3ba612 | 529 | @param right TimeSpan to add |
| ale87jan | 0:19609c3ba612 | 530 | @return New TimeSpan object, sum of left and right |
| ale87jan | 0:19609c3ba612 | 531 | */ |
| ale87jan | 0:19609c3ba612 | 532 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 533 | TimeSpan TimeSpan::operator+(const TimeSpan& right) |
| ale87jan | 0:19609c3ba612 | 534 | { |
| ale87jan | 0:19609c3ba612 | 535 | return TimeSpan(_seconds+right._seconds); |
| ale87jan | 0:19609c3ba612 | 536 | } |
| ale87jan | 0:19609c3ba612 | 537 | |
| ale87jan | 0:19609c3ba612 | 538 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 539 | /*! |
| ale87jan | 0:19609c3ba612 | 540 | @brief Subtract a TimeSpan |
| ale87jan | 0:19609c3ba612 | 541 | @param right TimeSpan to subtract |
| ale87jan | 0:19609c3ba612 | 542 | @return New TimeSpan object, right subtracted from left |
| ale87jan | 0:19609c3ba612 | 543 | */ |
| ale87jan | 0:19609c3ba612 | 544 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 545 | TimeSpan TimeSpan::operator-(const TimeSpan& right) |
| ale87jan | 0:19609c3ba612 | 546 | { |
| ale87jan | 0:19609c3ba612 | 547 | return TimeSpan(_seconds-right._seconds); |
| ale87jan | 0:19609c3ba612 | 548 | } |
| ale87jan | 0:19609c3ba612 | 549 | |
| ale87jan | 0:19609c3ba612 | 550 | |
| ale87jan | 0:19609c3ba612 | 551 | |
| ale87jan | 0:19609c3ba612 | 552 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 553 | /*! |
| ale87jan | 0:19609c3ba612 | 554 | @brief Convert a binary coded decimal value to binary. RTC stores time/date values as BCD. |
| ale87jan | 0:19609c3ba612 | 555 | @param val BCD value |
| ale87jan | 0:19609c3ba612 | 556 | @return Binary value |
| ale87jan | 0:19609c3ba612 | 557 | */ |
| ale87jan | 0:19609c3ba612 | 558 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 559 | static uint8_t bcd2bin (uint8_t val) |
| ale87jan | 0:19609c3ba612 | 560 | { |
| ale87jan | 0:19609c3ba612 | 561 | return val - 6 * (val >> 4); |
| ale87jan | 0:19609c3ba612 | 562 | } |
| ale87jan | 0:19609c3ba612 | 563 | |
| ale87jan | 0:19609c3ba612 | 564 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 565 | /*! |
| ale87jan | 0:19609c3ba612 | 566 | @brief Convert a binary value to BCD format for the RTC registers |
| ale87jan | 0:19609c3ba612 | 567 | @param val Binary value |
| ale87jan | 0:19609c3ba612 | 568 | @return BCD value |
| ale87jan | 0:19609c3ba612 | 569 | */ |
| ale87jan | 0:19609c3ba612 | 570 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 571 | static uint8_t bin2bcd (uint8_t val) |
| ale87jan | 0:19609c3ba612 | 572 | { |
| ale87jan | 0:19609c3ba612 | 573 | return val + 6 * (val / 10); |
| ale87jan | 0:19609c3ba612 | 574 | } |
| ale87jan | 0:19609c3ba612 | 575 | |
| ale87jan | 0:19609c3ba612 | 576 | |
| ale87jan | 0:19609c3ba612 | 577 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 578 | /*! |
| ale87jan | 0:19609c3ba612 | 579 | @brief Start I2C for the DS3231 and test succesful connection |
| ale87jan | 0:19609c3ba612 | 580 | @return True if Wire can find DS3231 or false otherwise. |
| ale87jan | 0:19609c3ba612 | 581 | */ |
| ale87jan | 0:19609c3ba612 | 582 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 583 | bool RTC_DS3231::begin(void) |
| ale87jan | 0:19609c3ba612 | 584 | { |
| ale87jan | 0:19609c3ba612 | 585 | |
| ale87jan | 0:19609c3ba612 | 586 | (*_i2c).frequency(100000); |
| ale87jan | 0:19609c3ba612 | 587 | char cmdData[1] = { (char)0x00 }; |
| ale87jan | 0:19609c3ba612 | 588 | |
| ale87jan | 0:19609c3ba612 | 589 | if ((*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData)) == 0) return true; |
| ale87jan | 0:19609c3ba612 | 590 | return false; |
| ale87jan | 0:19609c3ba612 | 591 | } |
| ale87jan | 0:19609c3ba612 | 592 | |
| ale87jan | 0:19609c3ba612 | 593 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 594 | /*! |
| ale87jan | 0:19609c3ba612 | 595 | @brief Check the status register Oscillator Stop Flag to see if the DS3231 stopped due to power loss |
| ale87jan | 0:19609c3ba612 | 596 | @return True if the bit is set (oscillator stopped) or false if it is running |
| ale87jan | 0:19609c3ba612 | 597 | */ |
| ale87jan | 0:19609c3ba612 | 598 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 599 | bool RTC_DS3231::lostPower(void) |
| ale87jan | 0:19609c3ba612 | 600 | { |
| ale87jan | 0:19609c3ba612 | 601 | return (read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG) >> 7); |
| ale87jan | 0:19609c3ba612 | 602 | } |
| ale87jan | 0:19609c3ba612 | 603 | |
| ale87jan | 0:19609c3ba612 | 604 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 605 | /*! |
| ale87jan | 0:19609c3ba612 | 606 | @brief Set the date and flip the Oscillator Stop Flag |
| ale87jan | 0:19609c3ba612 | 607 | @param dt DateTime object containing the date/time to set |
| ale87jan | 0:19609c3ba612 | 608 | */ |
| ale87jan | 0:19609c3ba612 | 609 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 610 | void RTC_DS3231::adjust(const DateTime& dt) |
| ale87jan | 0:19609c3ba612 | 611 | { |
| ale87jan | 0:19609c3ba612 | 612 | |
| ale87jan | 0:19609c3ba612 | 613 | char cmdData[8] = { (uint8_t)0,bin2bcd(dt.second()),bin2bcd(dt.minute()),bin2bcd(dt.hour()),bin2bcd(0),bin2bcd(dt.day()),bin2bcd(dt.month()),bin2bcd(dt.year() - 2000) }; |
| ale87jan | 0:19609c3ba612 | 614 | (*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData)); |
| ale87jan | 0:19609c3ba612 | 615 | /*(*_i2c).write(bin2bcd(dt.second())); |
| ale87jan | 0:19609c3ba612 | 616 | (*_i2c).write(bin2bcd(dt.minute())); |
| ale87jan | 0:19609c3ba612 | 617 | (*_i2c).write(bin2bcd(dt.hour())); |
| ale87jan | 0:19609c3ba612 | 618 | (*_i2c).write(bin2bcd(0)); |
| ale87jan | 0:19609c3ba612 | 619 | (*_i2c).write(bin2bcd(dt.day())); |
| ale87jan | 0:19609c3ba612 | 620 | (*_i2c).write(bin2bcd(dt.month())); |
| ale87jan | 0:19609c3ba612 | 621 | (*_i2c).write(bin2bcd(dt.year() - 2000));*/ |
| ale87jan | 0:19609c3ba612 | 622 | |
| ale87jan | 0:19609c3ba612 | 623 | uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG); |
| ale87jan | 0:19609c3ba612 | 624 | statreg &= ~0x80; // flip OSF bit |
| ale87jan | 0:19609c3ba612 | 625 | write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg); |
| ale87jan | 0:19609c3ba612 | 626 | } |
| ale87jan | 0:19609c3ba612 | 627 | |
| ale87jan | 0:19609c3ba612 | 628 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 629 | /*! |
| ale87jan | 0:19609c3ba612 | 630 | @brief Get the current date/time |
| ale87jan | 0:19609c3ba612 | 631 | @return DateTime object with the current date/time |
| ale87jan | 0:19609c3ba612 | 632 | */ |
| ale87jan | 0:19609c3ba612 | 633 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 634 | DateTime RTC_DS3231::now() |
| ale87jan | 0:19609c3ba612 | 635 | { |
| ale87jan | 0:19609c3ba612 | 636 | |
| ale87jan | 0:19609c3ba612 | 637 | uint8_t ss = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_SECONDS) & 0x7F); |
| ale87jan | 0:19609c3ba612 | 638 | uint8_t mm = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_MINUTES)); |
| ale87jan | 0:19609c3ba612 | 639 | uint8_t hh = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_HOURS)); |
| ale87jan | 0:19609c3ba612 | 640 | read_i2c_register(DS3231_ADDRESS, DS3231_DAY); |
| ale87jan | 0:19609c3ba612 | 641 | uint8_t d = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_DATE)); |
| ale87jan | 0:19609c3ba612 | 642 | uint8_t m = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_MONTH)); |
| ale87jan | 0:19609c3ba612 | 643 | uint16_t y = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_YEAR)) + 2000; |
| ale87jan | 0:19609c3ba612 | 644 | |
| ale87jan | 0:19609c3ba612 | 645 | return DateTime (y, m, d, hh, mm, ss); |
| ale87jan | 0:19609c3ba612 | 646 | } |
| ale87jan | 0:19609c3ba612 | 647 | |
| ale87jan | 0:19609c3ba612 | 648 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 649 | /*! |
| ale87jan | 0:19609c3ba612 | 650 | @brief Read the SQW pin mode |
| ale87jan | 0:19609c3ba612 | 651 | @return Pin mode, see Ds3231SqwPinMode enum |
| ale87jan | 0:19609c3ba612 | 652 | */ |
| ale87jan | 0:19609c3ba612 | 653 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 654 | Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() |
| ale87jan | 0:19609c3ba612 | 655 | { |
| ale87jan | 0:19609c3ba612 | 656 | int mode; |
| ale87jan | 0:19609c3ba612 | 657 | |
| ale87jan | 0:19609c3ba612 | 658 | mode = read_i2c_register(DS3231_ADDRESS, DS3231_SECONDS); |
| ale87jan | 0:19609c3ba612 | 659 | |
| ale87jan | 0:19609c3ba612 | 660 | mode &= 0x93; |
| ale87jan | 0:19609c3ba612 | 661 | return static_cast<Ds3231SqwPinMode>(mode); |
| ale87jan | 0:19609c3ba612 | 662 | } |
| ale87jan | 0:19609c3ba612 | 663 | |
| ale87jan | 0:19609c3ba612 | 664 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 665 | /*! |
| ale87jan | 0:19609c3ba612 | 666 | @brief Set the SQW pin mode |
| ale87jan | 0:19609c3ba612 | 667 | @param mode Desired mode, see Ds3231SqwPinMode enum |
| ale87jan | 0:19609c3ba612 | 668 | */ |
| ale87jan | 0:19609c3ba612 | 669 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 670 | void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) |
| ale87jan | 0:19609c3ba612 | 671 | { |
| ale87jan | 0:19609c3ba612 | 672 | uint8_t ctrl; |
| ale87jan | 0:19609c3ba612 | 673 | ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL); |
| ale87jan | 0:19609c3ba612 | 674 | |
| ale87jan | 0:19609c3ba612 | 675 | ctrl &= ~0x04; // turn off INTCON |
| ale87jan | 0:19609c3ba612 | 676 | ctrl &= ~0x18; // set freq bits to 0 |
| ale87jan | 0:19609c3ba612 | 677 | |
| ale87jan | 0:19609c3ba612 | 678 | if (mode == DS3231_OFF) { |
| ale87jan | 0:19609c3ba612 | 679 | ctrl |= 0x04; // turn on INTCN |
| ale87jan | 0:19609c3ba612 | 680 | } else { |
| ale87jan | 0:19609c3ba612 | 681 | ctrl |= mode; |
| ale87jan | 0:19609c3ba612 | 682 | } |
| ale87jan | 0:19609c3ba612 | 683 | write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, ctrl); |
| ale87jan | 0:19609c3ba612 | 684 | |
| ale87jan | 0:19609c3ba612 | 685 | //Serial.println( read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), HEX); |
| ale87jan | 0:19609c3ba612 | 686 | } |
| ale87jan | 0:19609c3ba612 | 687 | |
| ale87jan | 0:19609c3ba612 | 688 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 689 | /*! |
| ale87jan | 0:19609c3ba612 | 690 | @brief Get the current temperature from the DS3231's temperature sensor |
| ale87jan | 0:19609c3ba612 | 691 | @return Current temperature (float) |
| ale87jan | 0:19609c3ba612 | 692 | */ |
| ale87jan | 0:19609c3ba612 | 693 | /**************************************************************************/ |
| ale87jan | 0:19609c3ba612 | 694 | float RTC_DS3231::getTemperature() |
| ale87jan | 0:19609c3ba612 | 695 | { |
| ale87jan | 0:19609c3ba612 | 696 | uint8_t msb, lsb; |
| ale87jan | 0:19609c3ba612 | 697 | |
| ale87jan | 0:19609c3ba612 | 698 | msb = read_i2c_register(DS3231_ADDRESS, DS3231_TEMPREG1); |
| ale87jan | 0:19609c3ba612 | 699 | lsb = read_i2c_register(DS3231_ADDRESS, DS3231_TEMPREG2); |
| ale87jan | 0:19609c3ba612 | 700 | |
| ale87jan | 0:19609c3ba612 | 701 | // Serial.print("msb="); |
| ale87jan | 0:19609c3ba612 | 702 | // Serial.print(msb,HEX); |
| ale87jan | 0:19609c3ba612 | 703 | // Serial.print(", lsb="); |
| ale87jan | 0:19609c3ba612 | 704 | // Serial.println(lsb,HEX); |
| ale87jan | 0:19609c3ba612 | 705 | |
| ale87jan | 0:19609c3ba612 | 706 | return (float) msb + (lsb >> 6) * 0.25f; |
| ale87jan | 0:19609c3ba612 | 707 | } |
| ale87jan | 0:19609c3ba612 | 708 | |
| ale87jan | 0:19609c3ba612 | 709 | //****************************************************************************** |
| ale87jan | 0:19609c3ba612 | 710 | RTC_DS3231::RTC_DS3231(I2C *i2c): _i2c(i2c) |
| ale87jan | 0:19609c3ba612 | 711 | { |
| ale87jan | 0:19609c3ba612 | 712 | } |
| ale87jan | 0:19609c3ba612 | 713 | |
| ale87jan | 0:19609c3ba612 | 714 | //****************************************************************************** |
| ale87jan | 0:19609c3ba612 | 715 | RTC_DS3231::~RTC_DS3231() |
| ale87jan | 0:19609c3ba612 | 716 | { |
| ale87jan | 0:19609c3ba612 | 717 | } |