Fixed braindead style, added a 2038+ compatible timestamp
All checks were successful
Compile / Compile (push) Successful in 1m22s

This commit is contained in:
Lewis Jackson 2023-06-01 16:48:45 +03:00
parent 5993fda85e
commit 67ff091775
2 changed files with 521 additions and 444 deletions

View file

@ -38,27 +38,27 @@
#include <Arduino.h> #include <Arduino.h>
#include "Rtc_Pcf8563.h" #include "Rtc_Pcf8563.h"
Rtc_Pcf8563::Rtc_Pcf8563(void) Rtc_Pcf8563::Rtc_Pcf8563()
{ {
Wire.begin(); Wire.begin();
Rtcc_Addr = RTCC_R>>1; Rtcc_Addr = RTCC_R >> 1;
} }
Rtc_Pcf8563::Rtc_Pcf8563(int sdaPin, int sdlPin) Rtc_Pcf8563::Rtc_Pcf8563(int sdaPin, int sdlPin)
{ {
Wire.begin(sdaPin, sdlPin); Wire.begin(sdaPin, sdlPin);
Rtcc_Addr = RTCC_R>>1; Rtcc_Addr = RTCC_R >> 1;
} }
/* Private internal functions, but useful to look at if you need a similar func. */ /* Private internal functions, but useful to look at if you need a similar func. */
byte Rtc_Pcf8563::decToBcd(byte val) byte Rtc_Pcf8563::decToBcd(byte val)
{ {
return ( (val/10*16) + (val%10) ); return ((val / 10 * 16) + (val % 10));
} }
byte Rtc_Pcf8563::bcdToDec(byte val) byte Rtc_Pcf8563::bcdToDec(byte val)
{ {
return ( (val/16*10) + (val%16) ); return ((val / 16 * 10) + (val % 16));
} }
void Rtc_Pcf8563::zeroClock() void Rtc_Pcf8563::zeroClock()
@ -102,7 +102,7 @@ byte Rtc_Pcf8563::readStatus2()
return getStatus2(); return getStatus2();
} }
void Rtc_Pcf8563::clearVoltLow(void) void Rtc_Pcf8563::clearVoltLow()
{ {
getDateTime(); getDateTime();
// Only clearing is possible on device (I tried) // Only clearing is possible on device (I tried)
@ -114,7 +114,7 @@ void Rtc_Pcf8563::clearVoltLow(void)
/* /*
* Atomicly read all device registers in one operation * Atomicly read all device registers in one operation
*/ */
void Rtc_Pcf8563::getDateTime(void) void Rtc_Pcf8563::getDateTime()
{ {
/* Start at beginning, read entire memory in one go */ /* Start at beginning, read entire memory in one go */
Wire.beginTransmission(Rtcc_Addr); Wire.beginTransmission(Rtcc_Addr);
@ -124,8 +124,9 @@ void Rtc_Pcf8563::getDateTime(void)
/* As per data sheet, have to read everything all in one operation */ /* As per data sheet, have to read everything all in one operation */
uint8_t readBuffer[16] = {0}; uint8_t readBuffer[16] = {0};
Wire.requestFrom(Rtcc_Addr, 16); Wire.requestFrom(Rtcc_Addr, 16);
for (uint8_t i=0; i < 16; i++) for (uint8_t i=0; i < 16; i++) {
readBuffer[i] = Wire.read(); readBuffer[i] = Wire.read();
}
// status bytes // status bytes
status1 = readBuffer[0]; status1 = readBuffer[0];
@ -146,10 +147,12 @@ void Rtc_Pcf8563::getDateTime(void)
weekday = bcdToDec(readBuffer[6] & 0x07); weekday = bcdToDec(readBuffer[6] & 0x07);
//get raw month data byte and set month and century with it. //get raw month data byte and set month and century with it.
month = readBuffer[7]; month = readBuffer[7];
if (month & RTCC_CENTURY_MASK) if (month & RTCC_CENTURY_MASK) {
century = true; century = true;
else } else {
century = false; century = false;
}
//0x1f = 0b00011111 //0x1f = 0b00011111
month = month & 0x1f; month = month & 0x1f;
month = bcdToDec(month); month = bcdToDec(month);
@ -157,25 +160,31 @@ void Rtc_Pcf8563::getDateTime(void)
// alarm bytes // alarm bytes
alarm_minute = readBuffer[9]; alarm_minute = readBuffer[9];
if(B10000000 & alarm_minute) if(B10000000 & alarm_minute) {
alarm_minute = RTCC_NO_ALARM; alarm_minute = RTCC_NO_ALARM;
else } else {
alarm_minute = bcdToDec(alarm_minute & B01111111); alarm_minute = bcdToDec(alarm_minute & B01111111);
}
alarm_hour = readBuffer[10]; alarm_hour = readBuffer[10];
if(B10000000 & alarm_hour) if(B10000000 & alarm_hour) {
alarm_hour = RTCC_NO_ALARM; alarm_hour = RTCC_NO_ALARM;
else } else {
alarm_hour = bcdToDec(alarm_hour & B00111111); alarm_hour = bcdToDec(alarm_hour & B00111111);
}
alarm_day = readBuffer[11]; alarm_day = readBuffer[11];
if(B10000000 & alarm_day) if(B10000000 & alarm_day) {
alarm_day = RTCC_NO_ALARM; alarm_day = RTCC_NO_ALARM;
else } else {
alarm_day = bcdToDec(alarm_day & B00111111); alarm_day = bcdToDec(alarm_day & B00111111);
}
alarm_weekday = readBuffer[12]; alarm_weekday = readBuffer[12];
if(B10000000 & alarm_weekday) if(B10000000 & alarm_weekday) {
alarm_weekday = RTCC_NO_ALARM; alarm_weekday = RTCC_NO_ALARM;
else } else {
alarm_weekday = bcdToDec(alarm_weekday & B00000111); alarm_weekday = bcdToDec(alarm_weekday & B00000111);
}
// CLKOUT_control 0x03 = 0b00000011 // CLKOUT_control 0x03 = 0b00000011
squareWave = readBuffer[13] & 0x03; squareWave = readBuffer[13] & 0x03;
@ -196,10 +205,12 @@ void Rtc_Pcf8563::setDateTime(byte day, byte weekday, byte month,
1=19xx 1=19xx
*/ */
month = decToBcd(month); month = decToBcd(month);
if (century)
if (century) {
month |= RTCC_CENTURY_MASK; month |= RTCC_CENTURY_MASK;
else } else {
month &= ~RTCC_CENTURY_MASK; month &= ~RTCC_CENTURY_MASK;
}
/* As per data sheet, have to set everything all in one operation */ /* As per data sheet, have to set everything all in one operation */
Wire.beginTransmission(Rtcc_Addr); // Issue I2C start signal Wire.beginTransmission(Rtcc_Addr); // Issue I2C start signal
@ -270,7 +281,7 @@ void Rtc_Pcf8563::enableAlarm()
void Rtc_Pcf8563::setAlarm(byte min, byte hour, byte day, byte weekday) void Rtc_Pcf8563::setAlarm(byte min, byte hour, byte day, byte weekday)
{ {
getDateTime(); // operate on current values getDateTime(); // operate on current values
if (min <99) { if (min < 99) {
min = constrain(min, 0, 59); min = constrain(min, 0, 59);
min = decToBcd(min); min = decToBcd(min);
min &= ~RTCC_ALARM; min &= ~RTCC_ALARM;
@ -352,9 +363,12 @@ void Rtc_Pcf8563::resetAlarm()
// true if timer interrupt and control is enabled // true if timer interrupt and control is enabled
bool Rtc_Pcf8563::timerEnabled() bool Rtc_Pcf8563::timerEnabled()
{ {
if (getStatus2() & RTCC_TIMER_TIE) if (getStatus2() & RTCC_TIMER_TIE) {
if (timer_control & RTCC_TIMER_TE) if (timer_control & RTCC_TIMER_TE) {
return true; return true;
}
}
return false; return false;
} }
@ -367,7 +381,7 @@ bool Rtc_Pcf8563::timerActive()
// enable timer and interrupt // enable timer and interrupt
void Rtc_Pcf8563::enableTimer(void) void Rtc_Pcf8563::enableTimer()
{ {
getDateTime(); getDateTime();
//set TE to 1 //set TE to 1
@ -396,10 +410,12 @@ void Rtc_Pcf8563::enableTimer(void)
void Rtc_Pcf8563::setTimer(byte value, byte frequency, bool is_pulsed) void Rtc_Pcf8563::setTimer(byte value, byte frequency, bool is_pulsed)
{ {
getDateTime(); getDateTime();
if (is_pulsed) if (is_pulsed) {
status2 |= 0x01 << 4; status2 |= 0x01 << 4;
else } else {
status2 &= ~(0x01 << 4); status2 &= ~(0x01 << 4);
}
timer_value = value; timer_value = value;
// TE set to 1 in enableTimer(), leave 0 for now // TE set to 1 in enableTimer(), leave 0 for now
timer_control |= (frequency & RTCC_TIMER_TD10); // use only last 2 bits timer_control |= (frequency & RTCC_TIMER_TD10); // use only last 2 bits
@ -420,7 +436,7 @@ void Rtc_Pcf8563::setTimer(byte value, byte frequency, bool is_pulsed)
// clear timer flag and interrupt // clear timer flag and interrupt
void Rtc_Pcf8563::clearTimer(void) void Rtc_Pcf8563::clearTimer()
{ {
getDateTime(); getDateTime();
//set status2 TF val to zero //set status2 TF val to zero
@ -447,7 +463,7 @@ void Rtc_Pcf8563::clearTimer(void)
// clear timer flag but leave interrupt unchanged */ // clear timer flag but leave interrupt unchanged */
void Rtc_Pcf8563::resetTimer(void) void Rtc_Pcf8563::resetTimer()
{ {
getDateTime(); getDateTime();
//set status2 TF val to zero to reset timer //set status2 TF val to zero to reset timer
@ -511,17 +527,15 @@ const char *Rtc_Pcf8563::formatDate(byte style)
getDate(); getDate();
switch (style) { switch (style) {
case RTCC_DATE_ISO8601:
case RTCC_DATE_ASIA: if (century ) {
//do the asian style, yyyy-mm-dd
if (century ){
strDate[0] = '1'; strDate[0] = '1';
strDate[1] = '9'; strDate[1] = '9';
} } else {
else {
strDate[0] = '2'; strDate[0] = '2';
strDate[1] = '0'; strDate[1] = '0';
} }
strDate[2] = '0' + (year / 10 ); strDate[2] = '0' + (year / 10 );
strDate[3] = '0' + (year % 10); strDate[3] = '0' + (year % 10);
strDate[4] = '-'; strDate[4] = '-';
@ -533,21 +547,22 @@ const char *Rtc_Pcf8563::formatDate(byte style)
strDate[10] = '\0'; strDate[10] = '\0';
break; break;
case RTCC_DATE_US: case RTCC_DATE_US:
//the pitiful US style, mm/dd/yyyy // the utterly bonkers US style, mm/dd/yyyy
strDate[0] = '0' + (month / 10); strDate[0] = '0' + (month / 10);
strDate[1] = '0' + (month % 10); strDate[1] = '0' + (month % 10);
strDate[2] = '/'; strDate[2] = '/';
strDate[3] = '0' + (day / 10); strDate[3] = '0' + (day / 10);
strDate[4] = '0' + (day % 10); strDate[4] = '0' + (day % 10);
strDate[5] = '/'; strDate[5] = '/';
if (century){
if (century) {
strDate[6] = '1'; strDate[6] = '1';
strDate[7] = '9'; strDate[7] = '9';
} } else {
else {
strDate[6] = '2'; strDate[6] = '2';
strDate[7] = '0'; strDate[7] = '0';
} }
strDate[8] = '0' + (year / 10 ); strDate[8] = '0' + (year / 10 );
strDate[9] = '0' + (year % 10); strDate[9] = '0' + (year % 10);
strDate[10] = '\0'; strDate[10] = '\0';
@ -562,20 +577,20 @@ const char *Rtc_Pcf8563::formatDate(byte style)
strDate[4] = '0' + (month % 10); strDate[4] = '0' + (month % 10);
strDate[5] = '-'; strDate[5] = '-';
if (century){ if (century) {
strDate[6] = '1'; strDate[6] = '1';
strDate[7] = '9'; strDate[7] = '9';
} } else {
else {
strDate[6] = '2'; strDate[6] = '2';
strDate[7] = '0'; strDate[7] = '0';
} }
strDate[8] = '0' + (year / 10 ); strDate[8] = '0' + (year / 10 );
strDate[9] = '0' + (year % 10); strDate[9] = '0' + (year % 10);
strDate[10] = '\0'; strDate[10] = '\0';
break; break;
} }
return strDate; return strDate;
} }
@ -626,44 +641,53 @@ void Rtc_Pcf8563::getTime()
getDateTime(); getDateTime();
} }
bool Rtc_Pcf8563::getVoltLow(void) bool Rtc_Pcf8563::getVoltLow()
{ {
return volt_low; return volt_low;
} }
byte Rtc_Pcf8563::getSecond() { byte Rtc_Pcf8563::getSecond()
{
return sec; return sec;
} }
byte Rtc_Pcf8563::getMinute() { byte Rtc_Pcf8563::getMinute()
{
return minute; return minute;
} }
byte Rtc_Pcf8563::getHour() { byte Rtc_Pcf8563::getHour()
{
return hour; return hour;
} }
byte Rtc_Pcf8563::getAlarmMinute() { byte Rtc_Pcf8563::getAlarmMinute()
{
return alarm_minute; return alarm_minute;
} }
byte Rtc_Pcf8563::getAlarmHour() { byte Rtc_Pcf8563::getAlarmHour()
{
return alarm_hour; return alarm_hour;
} }
byte Rtc_Pcf8563::getAlarmDay() { byte Rtc_Pcf8563::getAlarmDay()
{
return alarm_day; return alarm_day;
} }
byte Rtc_Pcf8563::getAlarmWeekday() { byte Rtc_Pcf8563::getAlarmWeekday()
{
return alarm_weekday; return alarm_weekday;
} }
byte Rtc_Pcf8563::getTimerControl() { byte Rtc_Pcf8563::getTimerControl()
{
return timer_control; return timer_control;
} }
byte Rtc_Pcf8563::getTimerValue() { byte Rtc_Pcf8563::getTimerValue()
{
// Impossible to freeze this value, it could // Impossible to freeze this value, it could
// be changing during read. Multiple reads // be changing during read. Multiple reads
// required to check for consistency. // required to check for consistency.
@ -672,52 +696,62 @@ byte Rtc_Pcf8563::getTimerValue() {
last_value = timer_value; last_value = timer_value;
getDateTime(); getDateTime();
} while (timer_value != last_value); } while (timer_value != last_value);
return timer_value; return timer_value;
} }
byte Rtc_Pcf8563::getDay() { byte Rtc_Pcf8563::getDay()
{
return day; return day;
} }
byte Rtc_Pcf8563::getMonth() { byte Rtc_Pcf8563::getMonth()
{
return month; return month;
} }
byte Rtc_Pcf8563::getYear() { byte Rtc_Pcf8563::getYear()
{
return year; return year;
} }
bool Rtc_Pcf8563::getCentury() { bool Rtc_Pcf8563::getCentury()
{
return century; return century;
} }
byte Rtc_Pcf8563::getWeekday() { byte Rtc_Pcf8563::getWeekday()
{
return weekday; return weekday;
} }
byte Rtc_Pcf8563::getStatus1() { byte Rtc_Pcf8563::getStatus1()
{
return status1; return status1;
} }
byte Rtc_Pcf8563::getStatus2() { byte Rtc_Pcf8563::getStatus2()
{
return status2; return status2;
} }
unsigned long Rtc_Pcf8563::getTimestamp(){ unsigned long Rtc_Pcf8563::getTimestamp()
{
getDateTime(); // update date and time getDateTime(); // update date and time
unsigned long timestamp = 0; unsigned long timestamp = 0;
// Convert years in days // Convert years in days
timestamp = (year-epoch_year)*365; // convert years in days timestamp = (year-epoch_year) * 365; // convert years in days
if((year-epoch_year)>1) // add a dy when it's a leap year if((year-epoch_year)>1) { // add a dy when it's a leap year
{ for(unsigned char i = epoch_year; i<year;i++) {
for(unsigned char i = epoch_year; i<year;i++)
{
if(isLeapYear(century, i)) timestamp++; // add a day for each leap years if(isLeapYear(century, i)) timestamp++; // add a day for each leap years
} }
} }
if(month>2&&isLeapYear(century, year)) timestamp++; // test for the year's febuary
if(month>2 && isLeapYear(century, year)) {
timestamp++; // test for the year's febuary
}
// add months converted in days // add months converted in days
if(month>1) timestamp += months_days[month-2]; if(month>1) timestamp += months_days[month-2];
@ -725,11 +759,11 @@ unsigned long Rtc_Pcf8563::getTimestamp(){
// add days // add days
timestamp += (day-epoch_day); timestamp += (day-epoch_day);
timestamp*= 86400; // convert days in seconds timestamp *= 86400; // convert days in seconds
// convert time to second and add it to timestamp // convert time to second and add it to timestamp
unsigned long timeTemp = hour*60+ minute; unsigned long timeTemp = hour*60+ minute;
timeTemp *=60; timeTemp *= 60;
timeTemp += sec; timeTemp += sec;
timestamp += timeTemp; // add hours +minutes + seconds timestamp += timeTemp; // add hours +minutes + seconds
@ -738,3 +772,44 @@ unsigned long Rtc_Pcf8563::getTimestamp(){
return timestamp; return timestamp;
} }
uint64_t Rtc_Pcf8563::getTimestamp64()
{
getDateTime(); // update date and time
uint64_t timestamp = 0;
// Convert years in days
timestamp = (year - epoch_year) * 365; // convert years to days
if((year - epoch_year) > 1) { // add a day when it's a leap year
for(unsigned char i = epoch_year; i<year;i++) {
if(isLeapYear(century, i)) {
timestamp++; // add a day for each leap year
}
}
}
if(month > 2 && isLeapYear(century, year)) {
timestamp++; // test for the year's febuary
}
// add months converted in days
if(month > 1) {
timestamp += months_days[month-2];
}
// add days
timestamp += (day-epoch_day);
timestamp *= 86400; // convert days in seconds
// convert time to second and add it to timestamp
unsigned long timeTemp = hour * 60 + minute;
timeTemp *= 60;
timeTemp += sec;
timestamp += timeTemp; // add hours +minutes + seconds
timestamp += EPOCH_TIMESTAMP; // add epoch reference
return timestamp;
}

View file

@ -102,7 +102,8 @@
/* date format flags */ /* date format flags */
#define RTCC_DATE_WORLD 0x01 #define RTCC_DATE_WORLD 0x01
#define RTCC_DATE_ASIA 0x02 #define RTCC_DATE_ISO8601 0x02
#define RTCC_DATE_ASIA 0x02 // It's not "asian", it's ISO8601, that anybody with any sense uses
#define RTCC_DATE_US 0x04 #define RTCC_DATE_US 0x04
/* time format flags */ /* time format flags */
#define RTCC_TIME_HMS 0x01 #define RTCC_TIME_HMS 0x01
@ -198,6 +199,7 @@ class Rtc_Pcf8563 {
byte getTimerValue(); byte getTimerValue();
unsigned long getTimestamp(); // return unix timestamp unsigned long getTimestamp(); // return unix timestamp
uint64_t getTimestamp64(); // Fixed for 2038+
// Sets date/time to static fixed values, disable all alarms // Sets date/time to static fixed values, disable all alarms
// use zeroClock() above to guarantee lowest possible values instead. // use zeroClock() above to guarantee lowest possible values instead.