DS3231 based on Adafruit RTClib

Files at this revision

API Documentation at this revision

Comitter:
ale87jan
Date:
Thu Dec 19 12:57:00 2019 +0000
Commit message:
DS3231 based on RTClib from Adafruit

Changed in this revision

RTClib.cpp Show annotated file Show diff for this revision Revisions of this file
RTClib.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTClib.cpp	Thu Dec 19 12:57:00 2019 +0000
@@ -0,0 +1,717 @@
+/**************************************************************************/
+/*!
+  @file     RTClib.cpp
+
+  @mainpage Adafruit RTClib
+
+  @section intro Introduction
+
+  This is a fork of JeeLab's fantastic real time clock library for Arduino.
+
+  For details on using this library with an RTC module like the DS1307, PCF8523, or DS3231,
+  see the guide at: https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
+
+  Adafruit invests time and resources providing this open source code,
+  please support Adafruit and open-source hardware by purchasing
+  products from Adafruit!
+
+  @section classes Available classes
+
+  This library provides the following classes:
+
+  - Classes for manipulating dates, times and durations:
+    - DateTime represents a specific point in time; this is the data
+      type used for setting and reading the supported RTCs
+    - TimeSpan represents the length of a time interval
+  - Interfacing specific RTC chips:
+    - RTC_DS1307
+    - RTC_DS3231
+    - RTC_PCF8523
+  - RTC emulated in software; do not expect much accuracy out of these:
+    - RTC_Millis is based on `millis()`
+    - RTC_Micros is based on `micros()`; its drift rate can be tuned by
+      the user
+
+  @section license License
+
+  Original library by JeeLabs http://news.jeelabs.org/code/, released to the public domain.
+
+  This version: MIT (see LICENSE)
+*/
+/**************************************************************************/
+
+#include "mbed.h"
+#include <string>
+//using namespace std;
+#include "RTClib.h"
+
+/**************************************************************************/
+/*!
+    @brief  Read a uint8_t from an I2C register
+    @param addr I2C address
+    @param reg Register address
+    @return Register value
+*/
+/**************************************************************************/
+uint8_t RTC_DS3231::read_i2c_register(uint8_t addr, uint8_t reg)
+{
+
+    char cmdData[1] = { (char)reg };
+    char value;
+
+    (*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData));
+
+    (*_i2c).read(DS3231_ADDRESS, &value, 1);
+
+    return value;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Write a uint8_t to an I2C register
+    @param addr I2C address
+    @param reg Register address
+    @param val Value to write
+*/
+/**************************************************************************/
+void RTC_DS3231::write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val)
+{
+    char cmdData[2] = { (char)reg, val };
+
+    (*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData));
+
+}
+
+
+/**************************************************************************/
+// utility code, some of this could be exposed in the DateTime API if needed
+/**************************************************************************/
+
+/**
+  Number of days in each month, from January to November. December is not
+  needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time
+  library. C.f. https://github.com/adafruit/RTClib/issues/114
+*/
+const uint8_t daysInMonth [] = { 31,28,31,30,31,30,31,31,30,31,30 };
+
+/**************************************************************************/
+/*!
+    @brief  Given a date, return number of days since 2000/01/01, valid for 2001..2099
+    @param y Year
+    @param m Month
+    @param d Day
+    @return Number of days
+*/
+/**************************************************************************/
+static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d)
+{
+    if (y >= 2000)
+        y -= 2000;
+    uint16_t days = d;
+    for (uint8_t i = 1; i < m; ++i)
+        days += daysInMonth [i - 1];
+    if (m > 2 && y % 4 == 0)
+        ++days;
+    return days + 365 * y + (y + 3) / 4 - 1;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Given a number of days, hours, minutes, and seconds, return the total seconds
+    @param days Days
+    @param h Hours
+    @param m Minutes
+    @param s Seconds
+    @return Number of seconds total
+*/
+/**************************************************************************/
+static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s)
+{
+    return ((days * 24L + h) * 60 + m) * 60 + s;
+}
+
+
+
+/**************************************************************************/
+/*!
+    @brief  DateTime constructor from unixtime
+    @param t Initial time in seconds since Jan 1, 1970 (Unix time)
+*/
+/**************************************************************************/
+DateTime::DateTime (uint32_t t)
+{
+    t -= SECONDS_FROM_1970_TO_2000;    // bring to 2000 timestamp from 1970
+
+    ss = t % 60;
+    t /= 60;
+    mm = t % 60;
+    t /= 60;
+    hh = t % 24;
+    uint16_t days = t / 24;
+    uint8_t leap;
+    for (yOff = 0; ; ++yOff) {
+        leap = yOff % 4 == 0;
+        if (days < 365 + leap)
+            break;
+        days -= 365 + leap;
+    }
+    for (m = 1; m < 12; ++m) {
+        uint8_t daysPerMonth = daysInMonth [m - 1];
+        if (leap && m == 2)
+            ++daysPerMonth;
+        if (days < daysPerMonth)
+            break;
+        days -= daysPerMonth;
+    }
+    d = days + 1;
+}
+
+/**************************************************************************/
+/*!
+    @brief  DateTime constructor from Y-M-D H:M:S
+    @param year Year, 2 or 4 digits (year 2000 or higher)
+    @param month Month 1-12
+    @param day Day 1-31
+    @param hour 0-23
+    @param min 0-59
+    @param sec 0-59
+*/
+/**************************************************************************/
+DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
+{
+    if (year >= 2000)
+        year -= 2000;
+    yOff = year;
+    m = month;
+    d = day;
+    hh = hour;
+    mm = min;
+    ss = sec;
+}
+
+/**************************************************************************/
+/*!
+    @brief  DateTime copy constructor using a member initializer list
+    @param copy DateTime object to copy
+*/
+/**************************************************************************/
+DateTime::DateTime (const DateTime& copy):
+    yOff(copy.yOff),
+    m(copy.m),
+    d(copy.d),
+    hh(copy.hh),
+    mm(copy.mm),
+    ss(copy.ss)
+{}
+
+/**************************************************************************/
+/*!
+    @brief  Convert a string containing two digits to uint8_t, e.g. "09" returns 9
+    @param p Pointer to a string containing two digits
+*/
+/**************************************************************************/
+static uint8_t conv2d(const char* p)
+{
+    uint8_t v = 0;
+    if ('0' <= *p && *p <= '9')
+        v = *p - '0';
+    return 10 * v + *++p - '0';
+}
+
+/**************************************************************************/
+/*!
+    @brief  A convenient constructor for using "the compiler's time":
+            DateTime now (__DATE__, __TIME__);
+            NOTE: using F() would further reduce the RAM footprint, see below.
+    @param date Date string, e.g. "Dec 26 2009"
+    @param time Time string, e.g. "12:34:56"
+*/
+/**************************************************************************/
+DateTime::DateTime (const char* date, const char* time)
+{
+    // sample input: date = "Dec 26 2009", time = "12:34:56"
+    yOff = conv2d(date + 9);
+    // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
+    switch (date[0]) {
+        case 'J':
+            m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7);
+            break;
+        case 'F':
+            m = 2;
+            break;
+        case 'A':
+            m = date[2] == 'r' ? 4 : 8;
+            break;
+        case 'M':
+            m = date[2] == 'r' ? 3 : 5;
+            break;
+        case 'S':
+            m = 9;
+            break;
+        case 'O':
+            m = 10;
+            break;
+        case 'N':
+            m = 11;
+            break;
+        case 'D':
+            m = 12;
+            break;
+    }
+    d = conv2d(date + 4);
+    hh = conv2d(time);
+    mm = conv2d(time + 3);
+    ss = conv2d(time + 6);
+}
+
+/**************************************************************************/
+/*!
+    @brief  A convenient constructor for using "the compiler's time":
+            This version will save RAM by using PROGMEM to store it by using the F macro.
+            DateTime now (F(__DATE__), F(__TIME__));
+    @param date Date string, e.g. "Dec 26 2009"
+    @param time Time string, e.g. "12:34:56"
+*/
+/**************************************************************************/
+/*DateTime::DateTime (const __FlashstringHelper* date, const __FlashstringHelper* time) {
+    // sample input: date = "Dec 26 2009", time = "12:34:56"
+    char buff[11];
+    memcpy_P(buff, date, 11);
+    yOff = conv2d(buff + 9);
+    // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
+    switch (buff[0]) {
+        case 'J': m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7); break;
+        case 'F': m = 2; break;
+        case 'A': m = buff[2] == 'r' ? 4 : 8; break;
+        case 'M': m = buff[2] == 'r' ? 3 : 5; break;
+        case 'S': m = 9; break;
+        case 'O': m = 10; break;
+        case 'N': m = 11; break;
+        case 'D': m = 12; break;
+    }
+    d = conv2d(buff + 4);
+    memcpy_P(buff, time, 8);
+    hh = conv2d(buff);
+    mm = conv2d(buff + 3);
+    ss = conv2d(buff + 6);
+}*/
+
+/**************************************************************************/
+/*!
+    @brief  Return DateTime in based on user defined format.
+    @param buffer: array of char for holding the format description and the formatted DateTime.
+                   Before calling this method, the buffer should be initialized by the user with
+                   a format string, e.g. "YYYY-MM-DD hh:mm:ss". The method will overwrite
+                   the buffer with the formatted date and/or time.
+    @return a pointer to the provided buffer. This is returned for convenience,
+            in order to enable idioms such as Serial.println(now.tostring(buffer));
+*/
+/**************************************************************************/
+
+char* DateTime::tostring(char* buffer)
+{
+    for(int i=0; i<strlen(buffer)-1; i++) {
+        if(buffer[i] == 'h' && buffer[i+1] == 'h') {
+            buffer[i] = '0'+hh/10;
+            buffer[i+1] = '0'+hh%10;
+        }
+        if(buffer[i] == 'm' && buffer[i+1] == 'm') {
+            buffer[i] = '0'+mm/10;
+            buffer[i+1] = '0'+mm%10;
+        }
+        if(buffer[i] == 's' && buffer[i+1] == 's') {
+            buffer[i] = '0'+ss/10;
+            buffer[i+1] = '0'+ss%10;
+        }
+        if(buffer[i] == 'D' && buffer[i+1] =='D' && buffer[i+2] =='D') {
+            static const char day_names[] = "SunMonTueWedThuFriSat";
+            const uint8_t p = 3*dayOfTheWeek();
+            buffer[i] = day_names[p];
+            buffer[i+1] = day_names[p+1];
+            buffer[i+2] = day_names[p+2];
+        } else if(buffer[i] == 'D' && buffer[i+1] == 'D') {
+            buffer[i] = '0'+d/10;
+            buffer[i+1] = '0'+d%10;
+        }
+        if(buffer[i] == 'M' && buffer[i+1] =='M' && buffer[i+2] =='M') {
+            static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+            const uint8_t p = 3*(m-1);
+            buffer[i] = month_names[p];
+            buffer[i+1] = month_names[p+1];
+            buffer[i+2] = month_names[p+2];
+        } else if(buffer[i] == 'M' && buffer[i+1] == 'M') {
+            buffer[i] = '0'+m/10;
+            buffer[i+1] = '0'+m%10;
+        }
+        if(buffer[i] == 'Y'&& buffer[i+1] == 'Y'&& buffer[i+2] == 'Y'&& buffer[i+3] == 'Y') {
+            buffer[i] = '2';
+            buffer[i+1] = '0';
+            buffer[i+2] = '0'+(yOff/10)%10;
+            buffer[i+3] = '0'+yOff%10;
+        } else if(buffer[i] == 'Y'&& buffer[i+1] == 'Y') {
+            buffer[i] = '0'+(yOff/10)%10;
+            buffer[i+1] = '0'+yOff%10;
+        }
+
+    }
+    return buffer;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Return the day of the week for this object, from 0-6.
+    @return Day of week 0-6 starting with Sunday, e.g. Sunday = 0, Saturday = 6
+*/
+/**************************************************************************/
+uint8_t DateTime::dayOfTheWeek() const
+{
+    uint16_t day = date2days(yOff, m, d);
+    return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
+}
+
+/**************************************************************************/
+/*!
+    @brief  Return unix time, seconds since Jan 1, 1970.
+    @return Number of seconds since Jan 1, 1970
+*/
+/**************************************************************************/
+uint32_t DateTime::unixtime(void) const
+{
+    uint32_t t;
+    uint16_t days = date2days(yOff, m, d);
+    t = time2long(days, hh, mm, ss);
+    t += SECONDS_FROM_1970_TO_2000;  // seconds from 1970 to 2000
+
+    return t;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Convert the DateTime to seconds
+    @return The object as seconds since 2000-01-01
+*/
+/**************************************************************************/
+long DateTime::secondstime(void) const
+{
+    long t;
+    uint16_t days = date2days(yOff, m, d);
+    t = time2long(days, hh, mm, ss);
+    return t;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Add a TimeSpan to the DateTime object
+    @param span TimeSpan object
+    @return new DateTime object with span added to it
+*/
+/**************************************************************************/
+DateTime DateTime::operator+(const TimeSpan& span)
+{
+    return DateTime(unixtime()+span.totalseconds());
+}
+
+/**************************************************************************/
+/*!
+    @brief  Subtract a TimeSpan from the DateTime object
+    @param span TimeSpan object
+    @return new DateTime object with span subtracted from it
+*/
+/**************************************************************************/
+DateTime DateTime::operator-(const TimeSpan& span)
+{
+    return DateTime(unixtime()-span.totalseconds());
+}
+
+/**************************************************************************/
+/*!
+    @brief  Subtract one DateTime from another
+    @param right The DateTime object to subtract from self (the left object)
+    @return TimeSpan of the difference between DateTimes
+*/
+/**************************************************************************/
+TimeSpan DateTime::operator-(const DateTime& right)
+{
+    return TimeSpan(unixtime()-right.unixtime());
+}
+
+/**************************************************************************/
+/*!
+    @brief  Is one DateTime object less than (older) than the other?
+    @param right Comparison DateTime object
+    @return True if the left object is older than the right object
+*/
+/**************************************************************************/
+bool DateTime::operator<(const DateTime& right) const
+{
+    return unixtime() < right.unixtime();
+}
+
+/**************************************************************************/
+/*!
+    @brief  Is one DateTime object equal to the other?
+    @param right Comparison DateTime object
+    @return True if both DateTime objects are the same
+*/
+/**************************************************************************/
+bool DateTime::operator==(const DateTime& right) const
+{
+    return unixtime() == right.unixtime();
+}
+
+/**************************************************************************/
+/*!
+    @brief  ISO 8601 Timestamp
+    @param opt Format of the timestamp
+    @return Timestamp string, e.g. "2000-01-01T12:34:56"
+*/
+/**************************************************************************/
+string DateTime::timestamp(timestampOpt opt)
+{
+    char buffer[20];
+
+    //Generate timestamp according to opt
+    switch(opt) {
+        case TIMESTAMP_TIME:
+            //Only time
+            sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss);
+            break;
+        case TIMESTAMP_DATE:
+            //Only date
+            sprintf(buffer, "%d-%02d-%02d", 2000+yOff, m, d);
+            break;
+        default:
+            //Full
+            sprintf(buffer, "%d-%02d-%02dT%02d:%02d:%02d", 2000+yOff, m, d, hh, mm, ss);
+    }
+    return string(buffer);
+}
+
+
+
+/**************************************************************************/
+/*!
+    @brief  Create a new TimeSpan object in seconds
+    @param seconds Number of seconds
+*/
+/**************************************************************************/
+TimeSpan::TimeSpan (int32_t seconds):
+    _seconds(seconds)
+{}
+
+/**************************************************************************/
+/*!
+    @brief  Create a new TimeSpan object using a number of days/hours/minutes/seconds
+            e.g. Make a TimeSpan of 3 hours and 45 minutes: new TimeSpan(0, 3, 45, 0);
+    @param days Number of days
+    @param hours Number of hours
+    @param minutes Number of minutes
+    @param seconds Number of seconds
+*/
+/**************************************************************************/
+TimeSpan::TimeSpan (int16_t days, int8_t hours, int8_t minutes, int8_t seconds):
+    _seconds((int32_t)days*86400L + (int32_t)hours*3600 + (int32_t)minutes*60 + seconds)
+{}
+
+/**************************************************************************/
+/*!
+    @brief  Copy constructor, make a new TimeSpan using an existing one
+    @param copy The TimeSpan to copy
+*/
+/**************************************************************************/
+TimeSpan::TimeSpan (const TimeSpan& copy):
+    _seconds(copy._seconds)
+{}
+
+/**************************************************************************/
+/*!
+    @brief  Add two TimeSpans
+    @param right TimeSpan to add
+    @return New TimeSpan object, sum of left and right
+*/
+/**************************************************************************/
+TimeSpan TimeSpan::operator+(const TimeSpan& right)
+{
+    return TimeSpan(_seconds+right._seconds);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Subtract a TimeSpan
+    @param right TimeSpan to subtract
+    @return New TimeSpan object, right subtracted from left
+*/
+/**************************************************************************/
+TimeSpan TimeSpan::operator-(const TimeSpan& right)
+{
+    return TimeSpan(_seconds-right._seconds);
+}
+
+
+
+/**************************************************************************/
+/*!
+    @brief  Convert a binary coded decimal value to binary. RTC stores time/date values as BCD.
+    @param val BCD value
+    @return Binary value
+*/
+/**************************************************************************/
+static uint8_t bcd2bin (uint8_t val)
+{
+    return val - 6 * (val >> 4);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Convert a binary value to BCD format for the RTC registers
+    @param val Binary value
+    @return BCD value
+*/
+/**************************************************************************/
+static uint8_t bin2bcd (uint8_t val)
+{
+    return val + 6 * (val / 10);
+}
+
+
+/**************************************************************************/
+/*!
+    @brief  Start I2C for the DS3231 and test succesful connection
+    @return True if Wire can find DS3231 or false otherwise.
+*/
+/**************************************************************************/
+bool RTC_DS3231::begin(void)
+{
+
+    (*_i2c).frequency(100000);
+    char cmdData[1] = { (char)0x00 };
+
+    if ((*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData)) == 0) return true;
+    return false;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Check the status register Oscillator Stop Flag to see if the DS3231 stopped due to power loss
+    @return True if the bit is set (oscillator stopped) or false if it is running
+*/
+/**************************************************************************/
+bool RTC_DS3231::lostPower(void)
+{
+    return (read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG) >> 7);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Set the date and flip the Oscillator Stop Flag
+    @param dt DateTime object containing the date/time to set
+*/
+/**************************************************************************/
+void RTC_DS3231::adjust(const DateTime& dt)
+{
+
+    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) };
+    (*_i2c).write(DS3231_ADDRESS, cmdData, sizeof(cmdData));
+    /*(*_i2c).write(bin2bcd(dt.second()));
+    (*_i2c).write(bin2bcd(dt.minute()));
+    (*_i2c).write(bin2bcd(dt.hour()));
+    (*_i2c).write(bin2bcd(0));
+    (*_i2c).write(bin2bcd(dt.day()));
+    (*_i2c).write(bin2bcd(dt.month()));
+    (*_i2c).write(bin2bcd(dt.year() - 2000));*/
+
+    uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
+    statreg &= ~0x80; // flip OSF bit
+    write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Get the current date/time
+    @return DateTime object with the current date/time
+*/
+/**************************************************************************/
+DateTime RTC_DS3231::now()
+{
+
+    uint8_t ss = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_SECONDS) & 0x7F);
+    uint8_t mm = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_MINUTES));
+    uint8_t hh = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_HOURS));
+    read_i2c_register(DS3231_ADDRESS, DS3231_DAY);
+    uint8_t d = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_DATE));
+    uint8_t m = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_MONTH));
+    uint16_t y = bcd2bin(read_i2c_register(DS3231_ADDRESS, DS3231_YEAR)) + 2000;
+
+    return DateTime (y, m, d, hh, mm, ss);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Read the SQW pin mode
+    @return Pin mode, see Ds3231SqwPinMode enum
+*/
+/**************************************************************************/
+Ds3231SqwPinMode RTC_DS3231::readSqwPinMode()
+{
+    int mode;
+
+    mode = read_i2c_register(DS3231_ADDRESS, DS3231_SECONDS);
+
+    mode &= 0x93;
+    return static_cast<Ds3231SqwPinMode>(mode);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Set the SQW pin mode
+    @param mode Desired mode, see Ds3231SqwPinMode enum
+*/
+/**************************************************************************/
+void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode)
+{
+    uint8_t ctrl;
+    ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
+
+    ctrl &= ~0x04; // turn off INTCON
+    ctrl &= ~0x18; // set freq bits to 0
+
+    if (mode == DS3231_OFF) {
+        ctrl |= 0x04; // turn on INTCN
+    } else {
+        ctrl |= mode;
+    }
+    write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, ctrl);
+
+    //Serial.println( read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), HEX);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Get the current temperature from the DS3231's temperature sensor
+    @return Current temperature (float)
+*/
+/**************************************************************************/
+float RTC_DS3231::getTemperature()
+{
+    uint8_t msb, lsb;
+
+    msb = read_i2c_register(DS3231_ADDRESS, DS3231_TEMPREG1);
+    lsb = read_i2c_register(DS3231_ADDRESS, DS3231_TEMPREG2);
+
+//  Serial.print("msb=");
+//  Serial.print(msb,HEX);
+//  Serial.print(", lsb=");
+//  Serial.println(lsb,HEX);
+
+    return (float) msb + (lsb >> 6) * 0.25f;
+}
+
+//******************************************************************************
+RTC_DS3231::RTC_DS3231(I2C *i2c): _i2c(i2c)
+{
+}
+
+//******************************************************************************
+RTC_DS3231::~RTC_DS3231()
+{
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTClib.h	Thu Dec 19 12:57:00 2019 +0000
@@ -0,0 +1,291 @@
+/**************************************************************************/
+/*!
+  @file     RTClib.h
+
+  Original library by JeeLabs http://news.jeelabs.org/code/, released to the public domain
+
+  License: MIT (see LICENSE)
+
+  This is a fork of JeeLab's fantastic real time clock library for Arduino.
+
+  For details on using this library with an RTC module like the DS1307, PCF8523, or DS3231,
+  see the guide at: https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
+
+  Adafruit invests time and resources providing this open source code,
+  please support Adafruit and open-source hardware by purchasing
+  products from Adafruit!
+*/
+/**************************************************************************/
+
+#ifndef _RTCLIB_H_
+#define _RTCLIB_H_
+
+#include "mbed.h"
+#include <string>
+//using namespace std;
+class TimeSpan;
+
+#define DS3231_ADDRESS      0xD0    ///< I2C address for DS3231
+
+/** Registers */
+#define DS3231_SECONDS      0x00
+#define DS3231_MINUTES      0x01
+#define DS3231_HOURS        0x02
+#define DS3231_DAY          0x03
+#define DS3231_DATE         0x04
+#define DS3231_MONTH        0x05
+#define DS3231_YEAR         0x06
+#define DS3231_A1SEC        0x07
+#define DS3231_A1MIN        0x08
+#define DS3231_A1HOUR       0x09
+#define DS3231_A1DYDT       0x0A
+#define DS3231_A2MIN        0x0B
+#define DS3231_A2HOUR       0x0C
+#define DS3231_A2DYDT       0x0D
+#define DS3231_CONTROL      0x0E    ///< Control register
+#define DS3231_STATUSREG    0x0F    ///< Status register
+#define DS3231_AGINGOFFSET  0x10
+#define DS3231_TEMPREG1     0x11
+#define DS3231_TEMPREG2     0x12
+
+/** Constants */
+#define SECONDS_PER_DAY             86400L      ///< 60 * 60 * 24
+#define SECONDS_FROM_1970_TO_2000   946684800   ///< Unixtime for 2000-01-01 00:00:00, useful for initialization
+
+
+/**************************************************************************/
+/*!
+    @brief  Simple general-purpose date/time class (no TZ / DST / leap second handling!).
+            See http://en.wikipedia.org/wiki/Leap_second
+*/
+/**************************************************************************/
+class DateTime
+{
+public:
+    DateTime (uint32_t t = SECONDS_FROM_1970_TO_2000);
+    DateTime (uint16_t year, uint8_t month, uint8_t day,
+              uint8_t hour = 0, uint8_t min = 0, uint8_t sec = 0);
+    DateTime (const DateTime& copy);
+    DateTime (const char* date, const char* time);
+    //DateTime (const __FlashstringHelper* date, const __FlashstringHelper* time);
+    char* tostring(char* buffer);
+
+    /*!
+        @brief  Return the year, stored as an offset from 2000
+        @return uint16_t year
+    */
+    uint16_t year() const
+    {
+        return 2000 + yOff;
+    }
+    /*!
+        @brief  Return month
+        @return uint8_t month
+    */
+    uint8_t month() const
+    {
+        return m;
+    }
+    /*!
+        @brief  Return day
+        @return uint8_t day
+    */
+    uint8_t day() const
+    {
+        return d;
+    }
+    /*!
+        @brief  Return hours
+        @return uint8_t hours
+    */
+    uint8_t hour() const
+    {
+        return hh;
+    }
+    /*!
+        @brief  Return minutes
+        @return uint8_t minutes
+    */
+    uint8_t minute() const
+    {
+        return mm;
+    }
+    /*!
+        @brief  Return seconds
+        @return uint8_t seconds
+    */
+    uint8_t second() const
+    {
+        return ss;
+    }
+
+    uint8_t dayOfTheWeek() const;
+
+    /** 32-bit times as seconds since 1/1/2000 */
+    long secondstime() const;
+
+    /** 32-bit times as seconds since 1/1/1970 */
+    uint32_t unixtime(void) const;
+
+    /** ISO 8601 Timestamp function */
+    enum timestampOpt {
+        TIMESTAMP_FULL, // YYYY-MM-DDTHH:MM:SS
+        TIMESTAMP_TIME, // HH:MM:SS
+        TIMESTAMP_DATE  // YYYY-MM-DD
+    };
+    string timestamp(timestampOpt opt = TIMESTAMP_FULL);
+
+    DateTime operator+(const TimeSpan& span);
+    DateTime operator-(const TimeSpan& span);
+    TimeSpan operator-(const DateTime& right);
+    bool operator<(const DateTime& right) const;
+    /*!
+        @brief  Test if one DateTime is greater (later) than another
+        @param right DateTime object to compare
+        @return True if the left object is greater than the right object, false otherwise
+    */
+    bool operator>(const DateTime& right) const
+    {
+        return right < *this;
+    }
+    /*!
+        @brief  Test if one DateTime is less (earlier) than or equal to another
+        @param right DateTime object to compare
+        @return True if the left object is less than or equal to the right object, false otherwise
+    */
+    bool operator<=(const DateTime& right) const
+    {
+        return !(*this > right);
+    }
+    /*!
+        @brief  Test if one DateTime is greater (later) than or equal to another
+        @param right DateTime object to compare
+        @return True if the left object is greater than or equal to the right object, false otherwise
+    */
+    bool operator>=(const DateTime& right) const
+    {
+        return !(*this < right);
+    }
+    bool operator==(const DateTime& right) const;
+    /*!
+        @brief  Test if two DateTime objects not equal
+        @param right DateTime object to compare
+        @return True if the two objects are not equal, false if they are
+    */
+    bool operator!=(const DateTime& right) const
+    {
+        return !(*this == right);
+    }
+
+protected:
+    uint8_t yOff;   ///< Year offset from 2000
+    uint8_t m;      ///< Month 1-12
+    uint8_t d;      ///< Day 1-31
+    uint8_t hh;     ///< Hours 0-23
+    uint8_t mm;     ///< Minutes 0-59
+    uint8_t ss;     ///< Seconds 0-59
+};
+
+
+/**************************************************************************/
+/*!
+    @brief  Timespan which can represent changes in time with seconds accuracy.
+*/
+/**************************************************************************/
+class TimeSpan
+{
+public:
+    TimeSpan (int32_t seconds = 0);
+    TimeSpan (int16_t days, int8_t hours, int8_t minutes, int8_t seconds);
+    TimeSpan (const TimeSpan& copy);
+
+    /*!
+        @brief  Number of days in the TimeSpan
+                e.g. 4
+        @return int16_t days
+    */
+    int16_t days() const
+    {
+        return _seconds / 86400L;
+    }
+    /*!
+        @brief  Number of hours in the TimeSpan
+                This is not the total hours, it includes the days
+                e.g. 4 days, 3 hours - NOT 99 hours
+        @return int8_t hours
+    */
+    int8_t  hours() const
+    {
+        return _seconds / 3600 % 24;
+    }
+    /*!
+        @brief  Number of minutes in the TimeSpan
+                This is not the total minutes, it includes days/hours
+                e.g. 4 days, 3 hours, 27 minutes
+        @return int8_t minutes
+    */
+    int8_t  minutes() const
+    {
+        return _seconds / 60 % 60;
+    }
+    /*!
+        @brief  Number of seconds in the TimeSpan
+                This is not the total seconds, it includes the days/hours/minutes
+                e.g. 4 days, 3 hours, 27 minutes, 7 seconds
+        @return int8_t seconds
+    */
+    int8_t  seconds() const
+    {
+        return _seconds % 60;
+    }
+    /*!
+        @brief  Total number of seconds in the TimeSpan, e.g. 358027
+        @return int32_t seconds
+    */
+    int32_t totalseconds() const
+    {
+        return _seconds;
+    }
+
+    TimeSpan operator+(const TimeSpan& right);
+    TimeSpan operator-(const TimeSpan& right);
+
+protected:
+    int32_t _seconds;   ///< Actual TimeSpan value is stored as seconds
+};
+
+/** DS3231 SQW pin mode settings */
+enum Ds3231SqwPinMode {
+    DS3231_OFF            = 0x01, // Off
+    DS3231_SquareWave1Hz  = 0x00, // 1Hz square wave
+    DS3231_SquareWave1kHz = 0x08, // 1kHz square wave
+    DS3231_SquareWave4kHz = 0x10, // 4kHz square wave
+    DS3231_SquareWave8kHz = 0x18  // 8kHz square wave
+};
+
+/**************************************************************************/
+/*!
+    @brief  RTC based on the DS3231 chip connected via I2C and the Wire library
+*/
+/**************************************************************************/
+class RTC_DS3231
+{
+public:
+    RTC_DS3231(I2C *i2c);
+    ~RTC_DS3231();
+    bool begin(void);
+    void adjust(const DateTime& dt);
+    bool lostPower(void);
+    DateTime now();
+    Ds3231SqwPinMode readSqwPinMode();
+    void writeSqwPinMode(Ds3231SqwPinMode mode);
+    float getTemperature();  // in Celcius degree
+    uint8_t read_i2c_register(uint8_t addr, uint8_t reg);
+    void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) ;
+private:
+    // Internal Resources
+    I2C *_i2c;
+};
+
+
+#endif // _RTCLIB_H_