x

Dependents:   20180621_FT813

MCP79412.h

Committer:
JackB
Date:
2018-07-23
Revision:
0:04311b121ac4

File content as of revision 0:04311b121ac4:

/** mbded library for driving the PMAXIM DS3231 Real Time Clock
* datasheet link : http://datasheets.maximintegrated.com/en/ds/DS3231.pdf
* breakout       : MACETECH ChronoDot V2.1 High Precision RTC
* remi cormier 2012
* WARNING : sda and sdl should be pulled up with 2.2k resistor
*/

/** Example code
* @code
// DS3231 Library test program
// remi cormier 2012

#include "mbed.h"
#include "DS3231.h"

Serial pc(USBTX, USBRX);

int hour;
int minute;
int second;

int dayOfWeek;
int date;
int month;
int year;  
   
DS3231 RTC(p28,p27);


int main()
    {printf("\r\n\nDS3231 Library test program\r\nremi cormier 2012\r\n\n");
    
     RTC.setI2Cfrequency(400000);
    
     //RTC.writeRegister(DS3231_Aging_Offset,0); // uncomment to set Aging Offset 1LSB = approx. 0.1 ppm according from datasheet = 0.05 ppm @ 21 °C from my measurments
     
     RTC.convertTemperature();
      
     int reg=RTC.readRegister(DS3231_Aging_Offset);
     if (reg>127)
        {reg=reg-256;}
     pc.printf("Aging offset : %i\r\n",reg);
         
     pc.printf("OSF flag : %i",RTC.OSF());
     pc.printf("\r\n");
     
     RTC.readDate(&date,&month,&year);
     pc.printf("date : %02i-%02i-%02i",date,month,year);
     pc.printf("\r\n");
     
     //RTC.setTime(19,48,45); // uncomment to set time
     
     RTC.readTime(&hour,&minute,&second);
     pc.printf("time : %02i:%02i:%02i",hour,minute,second);
     pc.printf("\r\n");
     
     //RTC.setDate(6,22,12,2012); // uncomment to set date
     
     RTC.readDateTime(&dayOfWeek,&date,&month,&year,&hour,&minute,&second);
     pc.printf("date time : %i / %02i-%02i-%02i %02i:%02i:%02i",dayOfWeek,date,month,year,hour,minute,second);
     pc.printf("\r\n");
     
     pc.printf("temperature :%6.2f",RTC.readTemp());
     pc.printf("\r\n");
    }
* @endcode
*/

/*
http://www.cplusplus.com/reference/ctime/strftime/
%a   Abbreviated weekday name *  Thu
%A   Full weekday name * Thursday
%b   Abbreviated month name *    Aug
%B   Full month name *   August
%d   Day of the month, zero-padded (01-31)   23
%e   Day of the month, space-padded ( 1-31)  23
%F   Short YYYY-MM-DD date, equivalent to %Y-%m-%d   2001-08-23
%H   Hour in 24h format (00-23)  14
%j   Day of the year (001-366)   235
%m   Month as a decimal number (01-12)   08
%M   Minute (00-59)  55
%R   24-hour HH:MM time, equivalent to %H:%M 14:55
%S   Second (00-61)  02
%T   ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S 14:55:02
%u   ISO 8601 weekday as number with Monday as 1 (1-7)   4
%V   ISO 8601 week number (00-53)    34
%w   Weekday as a decimal number with Sunday as 0 (0-6)  4
%W   Week number with the first Monday as the first day of week one (00-53)  34
%X   Time representation *   14:55:02
%y   Year, last two digits (00-99)   01
%Y   Year    2001

http://www.cplusplus.com/reference/ctime/tm/
Member   Type    Meaning                        Range
tm_sec   int     seconds after the minute       0-61*
tm_min   int     minutes after the hour         0-59
tm_hour  int     hours since midnight           0-23
tm_mday  int     day of the month               1-31
tm_mon   int     months since January           0-11
tm_year  int     years since 1900    
tm_wday  int     days since Sunday              0-6     (0 = Sunday)
tm_yday  int     days since January 1           0-365
tm_isdst         int Daylight Saving Time flag   
The Daylight Saving Time flag (tm_isdst) is greater than zero if Daylight Saving Time is in effect,
zero if Daylight Saving Time is not in effect, and less than zero if the information is not available.
* tm_sec is generally 0-59. The extra range is to accommodate for leap seconds in certain systems.

http://www.epochconverter.com/programming/c
Convert from epoch to human readable date
    time_t     now;
    struct tm  ts;
    char       buf[80];
    // Get current time
    time(&now);
    // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz"
    ts = *localtime(&now);
    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
    printf("%s\n", buf);

Convert from human readable date to epoch
    struct tm t;
    time_t t_of_day;
    t.tm_year = 2011-1900;
    t.tm_mon = 7;           // Month, 0 - jan
    t.tm_mday = 8;          // Day of the month
    t.tm_hour = 16;
    t.tm_min = 11;
    t.tm_sec = 42;
    t.tm_isdst = -1;        // Is DST on? 1 = yes, 0 = no, -1 = unknown
    t_of_day = mktime(&t);
    printf("seconds since the Epoch: %ld\n", (long) t_of_day)

https://github.com/raburton/esp8266/blob/master/drivers/ds3231.c
https://github.com/raburton/esp8266/blob/master/drivers/ds3231.h

    // https://www.unixtimestamp.com/

*/
#include "mbed.h"
#include "macros.h"
#include "TableSummerTime.h"
#include "TableDayLight.h"

#ifndef __MCP79412__H_
#define __MCP79412__H_

// MCP7941x I2C Addresses
#define MCP79412_RTC_ADDR       0x6F
#define MCP79412_EEPROM_ADDR    0x57
#define MAC_LOCATION 0xF2   // Starts at 0xF0 but we are only interested in 6 bytes.
#define RTC_LOCATION 0x00

//MCP7941x Register Addresses
#define TIME_REG            0x00    // 7 registers, Seconds, Minutes, Hours, DOW, Date, Month, Year
#define DAY_REG             0x03    // the RTC Day register contains the OSCON, VBAT, and VBATEN bits
#define YEAR_REG            0x06    // RTC year register
#define CTRL_REG            0x07    // control register
#define CALIB_REG           0x08    // calibration register
#define UNLOCK_ID_REG       0x09    // unlock ID register
#define ALM0_REG            0x0A    // alarm 0, 6 registers, Seconds, Minutes, Hours, DOW, Date, Month
#define ALM1_REG            0x11    // alarm 1, 6 registers, Seconds, Minutes, Hours, DOW, Date, Month
#define ALM0_DAY            0x0D    // DOW register has alarm config/flag bits
#define PWRDWN_TS_REG       0x18    // power-down timestamp, 4 registers, Minutes, Hours, Date, Month
#define PWRUP_TS_REG        0x1C    // power-up timestamp, 4 registers, Minutes, Hours, Date, Month
#define TIMESTAMP_SIZE      8       // number of bytes in the two timestamp registers
#define SRAM_START_ADDR     0x20    // first SRAM address
#define SRAM_END_ADDR       0x5F    // last SRAM address
#define SRAM_SIZE           64      // number of bytes of SRAM
#define EEPROM_SIZE         128     // number of bytes of EEPROM
#define EEPROM_PAGE_SIZE    8       // number of bytes on an EEPROM page
#define UNIQUE_ID_ADDR      0xF0    // starting address for unique ID
#define UNIQUE_ID_SIZE      8       // number of bytes in unique ID

#define UNLOCK_ID_CODE1     0x55    // PROTECTED EEPROM UNLOCK SEQUENCE
#define UNLOCK_ID_CODE2     0xAA    // PROTECTED EEPROM UNLOCK SEQUENCE

//Control Register bits
#define OUT     7   // sets logic level on MFP when not used as square wave output
#define SQWE    6   // set to enable square wave output
#define ALM1    5   // alarm 1 is active
#define ALM0    4   // alarm 0 is active
#define EXTOSC  3   // set to drive the RTC registers from an external oscillator instead of a crystal
#define RS2     2   // RS2:0 set square wave output frequency: 0==1Hz, 1==4096Hz, 2==8192Hz, 3=32768Hz
#define RS1     1
#define RS0     0

//Other Control Bits
#define ST      7   // Seconds register (TIME_REG) oscillator start/stop bit, 1==Start, 0==Stop
#define HR1224  6   // Hours register (TIME_REG+2) 12 or 24 hour mode (24 hour mode==0)
#define AMPM    5   // Hours register (TIME_REG+2) AM/PM bit for 12 hour mode
#define OSCON   5   // Day register (TIME_REG+3) oscillator running (set and cleared by hardware)
#define VBAT    4   // Day register (TIME_REG+3) set by hardware when Vcc fails and RTC runs on battery.
                    // VBAT is cleared by software, clearing VBAT also clears the timestamp registers
#define VBATEN  3   // Day register (TIME_REG+3) VBATEN==1 enables backup battery, VBATEN==0 disconnects the VBAT pin (e.g. to save battery)
#define LP      5   // Month register (TIME_REG+5) leap year bit

//Alarm Control Bits
#define ALMPOL  7   // Alarm Polarity: Defines the logic level for the MFP when an alarm is triggered.
#define ALMC2   6   // Alarm configuration bits determine how alarms match. See ALM_MATCH defines below.
#define ALMC1   5
#define ALMC0   4
#define ALMIF   3   // Alarm Interrupt Flag: Set by hardware when an alarm was triggered, cleared by software.
// Note ALM_MATCH_DAY triggers alarm at midnight
#define ALARM_0 0   // constants for calling functions
#define ALARM_1 1

#define MCP79412_SET        0
#define MCP79412_CLEAR      1
#define MCP79412_REPLACE    2

#define NTP_OFFSET          2208988800ULL

//convenience macros to convert to and from tm years 
#define  tmYearToCalendar(Y) ((Y) + 1970)  // full four digit year 
#define  CalendarYrToTm(Y)   ((Y) - 1970)
#define  tmYearToY2k(Y)      ((Y) - 30)    // offset is from 2000
#define  y2kYearToTm(Y)      ((Y) + 30)   

enum Sqwave {
    SQWAVE_1_HZ, 
    SQWAVE_4096_HZ, 
    SQWAVE_8192_HZ, 
    SQWAVE_32768_HZ, 
    SQWAVE_NONE
};

enum {
    ALM_MATCH_SECONDS, 
    ALM_MATCH_MINUTES, 
    ALM_MATCH_HOURS, 
    ALM_MATCH_DAY, 
    ALM_MATCH_DATE, 
    ALM_RESERVED_5, 
    ALM_RESERVED_6, 
    ALM_MATCH_DATETIME, 
    ALM_DISABLE
};

typedef struct DateTime {
       int year;
       int mon;
       int mday;
       int wday;
       int yday;
       int hour;
       int min;
       int sec;
};

class MCP79412 {
public:
    DateTime datetime;
    struct tm *t;
    time_t secondsEpoch;
    uint8_t second, minute, hour, dayOfWeek, dayOfMonth, month, year;

    MCP79412(PinName sda, PinName scl);
    void setI2Cfrequency(int freq);
    bool getFlag(char reg, char mask, char *flag);
    void setFlag(char reg, char bits, char mode);
    int readRegister(char reg);
    void readRegisters(char reg, char *outbuf, char length);
    void writeRegister(int reg, char byte);
    void writeRegisters(int reg, char *inbuf, char length);
    void getMacAddress(char *mac_address);
    void writeMacAddress(char *mac_address);
    void unlockUniqueID();
    void setRtcDateTime(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfWeek, uint8_t dayOfMonth, uint8_t month, uint8_t year);
    void getRtcDateTime(uint8_t *second, uint8_t *minute, uint8_t *hour, uint8_t *dayOfWeek, uint8_t *dayOfMonth, uint8_t *month, uint8_t *year);
    bool checkTimeLost(void);
    void enableClock();
    void disableClock();
    void enableBattery();

    void writeRamByte(uint8_t location, uint8_t data);
    uint8_t writeRamBytes(uint8_t location, uint8_t *data, uint8_t length);
    uint8_t readRamByte(uint8_t location);
    uint8_t readRamBytes(uint8_t location, uint8_t *data, uint8_t length);

    void writeSramByte(uint8_t location, uint8_t data);
    uint8_t writeSramBytes(uint8_t location, uint8_t *data, uint8_t length);
    uint8_t readSramByte(uint8_t location);
    uint8_t readSramBytes(uint8_t location, uint8_t *data, uint8_t length);

    void writeEepromByte(uint8_t location, uint8_t data);
    uint8_t writeEepromBytes(uint8_t location, uint8_t *data, uint8_t length);
    uint8_t readEepromByte(uint8_t location);
    uint8_t readEepromBytes(uint8_t location, uint8_t *data, uint8_t length);
    
    int calibRead(void);
    void calibWrite(int value);
    void readUniqueId(char *uniqueID);
    void getEUI64(char *uniqueID);
    bool powerFail(time_t *powerDown, time_t *powerUp);
    void squareWave(Sqwave freq);
    void setAlarm(uint8_t alarmNumber, time_t alarmTime);
    void enableAlarm(uint8_t alarmNumber, uint8_t alarmType);
    bool alarm(uint8_t alarmNumber);
    void out(bool level);
    void alarmPolarity(bool polarity);
    bool isRunning(void);
    void vbaten(bool enable);
    
//    bool getSummerTime(void);
//    int dayOfYearC(void);
//    char * getSunRise(void);
//    char * getSunSet(void);
//    char * getDayLength(void);
//    int getSunRiseMinute(void);
//    int getSunSetMinute(void);
//    bool checkSunRise(void);
    
    void substr(char *s, char *d, int pos, int len);
    char * substr(char *s, int pos, int len);
    
    // Mbed dateTime
    struct tm setSystemDateTime(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfMonth, uint8_t month, uint8_t year);
    void getSystemDateTime(uint8_t *second, uint8_t *minute, uint8_t *hour, uint8_t *dayOfWeek, uint8_t *dayOfMonth, uint8_t *month, uint8_t *year);
    void setRtcToSystemDateTime(void);
    void setSystemToRtcDateTime(void);
    void setRtcFromTm(struct tm *t);
    struct tm getTmFromRtc(void);
    
    time_t getSecondsEpoch(void);
    void setSecondsEpoch(time_t t);

    void getRtcDateTimeAsTm(void);
    time_t convertDateTimeToTimestamp(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfMonth, uint8_t month, uint8_t year);
    uint8_t getWeekdayFromDate(uint8_t dayOfMonth, uint8_t month, uint8_t year);

    int bcd2dec(int k); // bcd to decimal conversion
    int dec2bcd(int k); // decimal to bcd conversion
    int decToBcd(int val);
    int bcdToDec(int val);
    
private :
    I2C _i2c;
    char _address_RTC;
    char buffer[32];
    bool _error;


};

#endif