SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
SensorRTC.h
Go to the documentation of this file.
1
30#pragma once
31
32#include "../SensorBuildOpt.h"
33#if !SENSORLIB_EXCLUDE_RTC_COMMON
34
35#include <sys/time.h>
36#include "SensorPlatform.hpp"
37
38typedef enum {
39 DT_FMT_HM, // Format Style : Hour:Minute
40 DT_FMT_HMS, // Format Style : Hour:Minute:Second
41 DT_FMT_YMD, // Format Style : Year-Month-Day
42 DT_FMT_MDY, // Format Style : Month-Day-Year
43 DT_FMT_DMY, // Format Style : Day-Month-Year
44 DT_FMT_YMD_HMS, // Format Style : Year-Month-Day/Hour:Minute:Second
45 DT_FMT_YMD_HMS_WEEK // Format Style : Year-Month-Day/Hour:Minute:Second - Weekday
47
49{
50 enum Month {
51 JANUARY = 1,
52 FEBRUARY,
53 MARCH,
54 APRIL,
55 MAY,
56 JUNE,
57 JULY,
58 AUGUST,
59 SEPTEMBER,
60 OCTOBER,
61 NOVEMBER,
62 DECEMBER
63 };
64
65public:
66 RTC_DateTime() : year(0), month(0), day(0), hour(0), minute(0), second(0), week(0) {}
67
68 RTC_DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint8_t week = 0) :
69 year(year), month(month), day(day), hour(hour), minute(minute), second(second), week(week) {}
70
71 RTC_DateTime(struct tm info) : year(info.tm_year + 1900), month(info.tm_mon + 1), day(info.tm_mday),
72 hour(info.tm_hour), minute(info.tm_min), second(info.tm_sec), week(info.tm_wday) {}
73
74 RTC_DateTime(const char *date, const char *time)
75 {
76 if (date == nullptr || time == nullptr) {
77 year = 0;
78 month = 0;
79 day = 0;
80 hour = 0;
81 minute = 0;
82 second = 0;
83 week = 0;
84 return;
85 }
86 // sample input: date = "Dec 26 2009", time = "12:34:56"
87 year = 2000 + parseStringToUint8(date + 9);
88 switch (date[0]) {
89 case 'J':
90 if ( date[1] == 'a' )
91 month = JANUARY;
92 else if ( date[2] == 'n' )
93 month = JUNE;
94 else
95 month = JULY;
96 break;
97 case 'F':
98 month = FEBRUARY;
99 break;
100 case 'A':
101 month = date[1] == 'p' ? APRIL : AUGUST;
102 break;
103 case 'M':
104 month = date[2] == 'r' ? MARCH : MAY;
105 break;
106 case 'S':
107 month = SEPTEMBER;
108 break;
109 case 'O':
110 month = OCTOBER;
111 break;
112 case 'N':
113 month = NOVEMBER;
114 break;
115 case 'D':
116 month = DECEMBER;
117 break;
118 }
119 day = parseStringToUint8(date + 4);
120 hour = parseStringToUint8(time);
121 minute = parseStringToUint8(time + 3);
122 second = parseStringToUint8(time + 6);
123 }
124
126 {
127 return ((d.year == year) && (d.month == month) && (d.day == day)
128 && (d.hour == hour) && (d.minute == minute));
129 }
130
131 struct tm toUnixTime()
132 {
133 struct tm t_tm;
134 t_tm.tm_hour = hour;
135 t_tm.tm_min = minute;
136 t_tm.tm_sec = second;
137 t_tm.tm_year = year - 1900; //Year, whose value starts from 1900
138 t_tm.tm_mon = month - 1; //Month (starting from January, 0 for January) - Value range is [0,11]
139 t_tm.tm_mday = day;
140 t_tm.tm_wday = week;
141 return t_tm;
142 }
143
144 // *INDENT-OFF*
145 uint16_t getYear() const { return year; }
146 uint8_t getMonth() const { return month; }
147 uint8_t getDay() const { return day; }
148 uint8_t getHour() const { return hour; }
149 uint8_t getMinute() const { return minute; }
150 uint8_t getSecond() const { return second; }
151 uint8_t getWeek() const { return week; }
152 // char getAMPM() const { return AMPM; }
153 // bool isAvailable() const { return available; }
154 // *INDENT-ON*
155
156private:
157 // *INDENT-OFF*
158 // void setAMPM(char ampm) { AMPM = ampm; }
159 // void setAvailable(bool avail) { available = avail; }
160 // *INDENT-ON*
161
162 uint16_t year;
163 uint8_t month;
164 uint8_t day;
165 uint8_t hour;
166 uint8_t minute;
167 uint8_t second;
168 uint8_t week;
169 // char AMPM;
170 // bool available;
171
172 uint8_t parseStringToUint8(const char *pString)
173 {
174 uint8_t value = 0;
175
176 // skip leading 0 and spaces
177 while ('0' == *pString || *pString == ' ') {
178 pString++;
179 }
180
181 // calculate number until we hit non-numeral char
182 while ('0' <= *pString && *pString <= '9') {
183 value *= 10;
184 value += *pString - '0';
185 pString++;
186 }
187 return value;
188 }
189};
190
192{
193public:
194 RTC_Alarm(void): second(0), minute(0), hour(0), day(0), week(0) {}
195 RTC_Alarm(uint8_t hour, uint8_t minute, uint8_t second, uint8_t day, uint8_t week ) :
196 second(second), minute(minute), hour(hour), day(day), week(week) {}
197
198 // *INDENT-OFF*
199 uint8_t getDay() const { return day; }
200 uint8_t getHour() const { return hour; }
201 uint8_t getMinute() const { return minute; }
202 uint8_t getSecond() const { return second; }
203 uint8_t getWeek() const { return week; }
204 // *INDENT-ON*
205
206private:
207 uint8_t second;
208 uint8_t minute;
209 uint8_t hour;
210 uint8_t day;
211 uint8_t week;
212};
213
215{
216public:
217
218#if defined(ARDUINO)
231 virtual bool begin(TwoWire &wire, int sda, int scl) = 0;
232
233#elif defined(ESP_PLATFORM)
234
235#if defined(SENSORLIB_USE_I2C_LEGACY)
236
250 virtual bool begin(i2c_port_t port_num, int sda, int scl) = 0;
251#else
252
263 virtual bool begin(i2c_master_bus_handle_t handle) = 0;
264#endif
265#endif // defined(ARDUINO)
266
278 virtual bool begin(SensorCommCustom::CustomCallback callback) = 0;
279
288 virtual void setDateTime(RTC_DateTime datetime) = 0;
289
299
308 virtual const char *getChipName() = 0;
309
310
316 virtual void reset() {};
317
318
335 void getDateTime(struct tm*info)
336 {
337 if (!info)return;
338 RTC_DateTime datetime = getDateTime();
339 *info = datetime.toUnixTime();
340 }
341
351 void setDateTime(uint16_t year, uint8_t month, uint8_t day,
352 uint8_t hour, uint8_t minute, uint8_t second)
353 {
354 setDateTime(RTC_DateTime(year, month, day, hour, minute, second));
355 }
356
373 {
374 const char *formatStr = NULL;
375 static char format[FORMAT_BUFFER_SIZE];
376
378
379 switch (style) {
380 case DT_FMT_HM:
381 formatStr = "%02d:%02d";
382 break;
383 case DT_FMT_HMS:
384 formatStr = "%02d:%02d:%02d";
385 break;
386 case DT_FMT_YMD:
387 formatStr = "%d-%02d-%02d";
388 break;
389 case DT_FMT_MDY:
390 formatStr = "%02d-%02d-%d";
391 break;
392 case DT_FMT_DMY:
393 formatStr = "%02d-%02d-%d";
394 break;
395 case DT_FMT_YMD_HMS:
396 formatStr = "%d-%02d-%02d/%02d:%02d:%02d";
397 break;
399 formatStr = "%d-%02d-%02d/%02d:%02d:%02d - %s";
400 break;
401 default:
402 formatStr = "%02d:%02d";
403 break;
404 }
405 int result = formatDateTime(formatStr, format, FORMAT_BUFFER_SIZE, &t);
406 if (result < 0 || (size_t)result >= FORMAT_BUFFER_SIZE) {
407 format[0] = '\0';
408 }
409 return format;
410 }
411
427 time_t hwClockRead(const timezone *tz = NULL)
428 {
429 struct timeval val;
430 // Retrieve the date and time from the RTC chip and convert it to a struct tm structure
431 struct tm t_tm = getDateTime().toUnixTime();
432 // Convert the struct tm structure to a Unix timestamp
433 time_t timestamp = mktime(&t_tm);
434 // Check if the mktime conversion was successful
435 if (timestamp == -1) {
436 SENSORLIB_LOG_E("mktime failed");
437 return -1;
438 }
439 val.tv_sec = timestamp;
440 val.tv_usec = 0;
441#if __BSD_VISIBLE
442 // On supported BSD systems, attempt to set the new time to the system clock
443 if (settimeofday(&val, tz) == -1) {
444 SENSORLIB_LOG_E("settimeofday failed");
445 }
446#endif /*__BSD_VISIBLE*/
447 // Return the converted Unix timestamp
448 return val.tv_sec;
449 }
450
457 {
458 time_t now;
459 struct tm info;
460 // Get the current system time as a Unix timestamp
461 now = time(NULL);
462 if (now == -1) {
463 SENSORLIB_LOG_E("time failed");
464 return -1;
465 }
466 if (localtime_r(&now, &info) == NULL) {
467 SENSORLIB_LOG_E("localtime_r failed");
468 return -1;
469 }
470 setDateTime(info);
471 return 0;
472 }
473
483 uint32_t getDayOfWeek(uint32_t day, uint32_t month, uint32_t year)
484 {
485 if (day < 1 || day > 31 || month < 1 || month > 12) {
486 return 0xFF;
487 }
488 if (month < 3) {
489 month += 12;
490 year--;
491 }
492 // Evaluate the parts of Zeller's congruence formula
493 uint32_t part1 = day;
494 uint32_t part2 = ((month + 1) * 26) / 10;
495 uint32_t part3 = year;
496 uint32_t part4 = year / 4;
497 uint32_t part5 = 6 * (year / 100);
498 uint32_t part6 = year / 400;
499
500 uint32_t val = (part1 + part2 + part3 + part4 + part5 + part6) % 7;
501
502 if (val == 0) {
503 val = 7;
504 }
505 return val - 1;
506 }
507
514 uint8_t getNextMonth(uint8_t curMonth)
515 {
516 return ((curMonth < 12u) ? (curMonth + 1u) : 1u);
517 }
518
525 uint16_t getNextYear(uint16_t curYear)
526 {
527 return (curYear + 1u);
528 }
529
536 uint32_t getLeapYear(uint32_t year)
537 {
538 uint32_t isDivisibleBy4 = (year % 4 == 0);
539 uint32_t isDivisibleBy100 = (year % 100 == 0);
540 uint32_t isDivisibleBy400 = (year % 400 == 0);
541
542 return (isDivisibleBy4 && !isDivisibleBy100) || isDivisibleBy400;
543 }
544
552 uint8_t getDaysInMonth(uint8_t month, uint16_t year)
553 {
554 constexpr uint8_t DAYS_IN_JANUARY = (31u);
555 constexpr uint8_t DAYS_IN_FEBRUARY = (28u);
556 constexpr uint8_t DAYS_IN_MARCH = (31u);
557 constexpr uint8_t DAYS_IN_APRIL = (30u);
558 constexpr uint8_t DAYS_IN_MAY = (31u);
559 constexpr uint8_t DAYS_IN_JUNE = (30u);
560 constexpr uint8_t DAYS_IN_JULY = (31u);
561 constexpr uint8_t DAYS_IN_AUGUST = (31u);
562 constexpr uint8_t DAYS_IN_SEPTEMBER = (30u);
563 constexpr uint8_t DAYS_IN_OCTOBER = (31u);
564 constexpr uint8_t DAYS_IN_NOVEMBER = (30u);
565 constexpr uint8_t DAYS_IN_DECEMBER = (31u);
566
567 const uint8_t daysInMonthTable[12] = {DAYS_IN_JANUARY,
568 DAYS_IN_FEBRUARY,
569 DAYS_IN_MARCH,
570 DAYS_IN_APRIL,
571 DAYS_IN_MAY,
572 DAYS_IN_JUNE,
573 DAYS_IN_JULY,
574 DAYS_IN_AUGUST,
575 DAYS_IN_SEPTEMBER,
576 DAYS_IN_OCTOBER,
577 DAYS_IN_NOVEMBER,
578 DAYS_IN_DECEMBER
579 };
580
581 uint8_t val = daysInMonthTable[month - 1u];
582 if (2 == month) {
583 if (0u != getLeapYear(year)) {
584 val++;
585 }
586 }
587 return val;
588 }
589
601 void convertUtcToTimezone(int &year, int &month, int &day, int &hour, int &minute, int &second, int timezoneOffsetSeconds)
602 {
603 if (year < 0 || month < 1 || month > 12 || day < 1 || day > getDaysInMonth(month, year) ||
604 hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
605 SENSORLIB_LOG_E("Invalid date or time input");
606 return;
607 }
608
609 int totalSeconds = hour * 3600 + minute * 60 + second;
610 totalSeconds += timezoneOffsetSeconds;
611
612 int daysOffset = totalSeconds / (24 * 3600);
613 totalSeconds %= (24 * 3600);
614
615 adjustDate(year, month, day, daysOffset);
616
617 if (totalSeconds < 0) {
618 totalSeconds += 24 * 3600;
619 adjustDate(year, month, day, -1);
620 }
621
622 hour = totalSeconds / 3600;
623 minute = (totalSeconds % 3600) / 60;
624 second = totalSeconds % 60;
625 }
626
633 void convertUtcToTimezone(struct tm& utcTime, int timezoneOffsetSeconds)
634 {
635 int year = utcTime.tm_year + 1900;
636 int month = utcTime.tm_mon + 1;
637 int day = utcTime.tm_mday;
638 int hour = utcTime.tm_hour;
639 int minute = utcTime.tm_min;
640 int second = utcTime.tm_sec;
641
642 convertUtcToTimezone(year, month, day, hour, minute, second, timezoneOffsetSeconds);
643
644 utcTime.tm_year = year - 1900;
645 utcTime.tm_mon = month - 1;
646 utcTime.tm_mday = day;
647 utcTime.tm_hour = hour;
648 utcTime.tm_min = minute;
649 utcTime.tm_sec = second;
650 }
651
657 static uint8_t BCD2DEC(uint8_t val)
658 {
659 return ((val >> 4) * 10) + (val & 0x0F);
660 }
661
667 static uint8_t DEC2BCD(uint8_t val)
668 {
669 return ((val / 10) << 4) | (val % 10);
670 }
671
672private:
673
674 static const size_t FORMAT_BUFFER_SIZE = 64;
675
676
677 void adjustDate(int &year, int &month, int &day, int daysOffset)
678 {
679 day += daysOffset;
680 while (day > getDaysInMonth(month, year)) {
681 day -= getDaysInMonth(month, year);
682 month++;
683 if (month > 12) {
684 year++;
685 month = 1;
686 }
687 }
688 while (day < 1) {
689 month--;
690 if (month < 1) {
691 year--;
692 month = 12;
693 }
694 day += getDaysInMonth(month, year);
695 }
696 }
697
698 int formatDateTime(const char *fmt, char *buffer, size_t bufferSize, const RTC_DateTime *t)
699 {
700 const char *weekString[] = {"Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"};
701 if (!fmt || !buffer || bufferSize == 0 || !t) {
702 return -1;
703 }
704 return snprintf(buffer, bufferSize, fmt, t->getYear(), t->getMonth(), t->getDay(),
705 t->getHour(), t->getMinute(), t->getSecond(),
706 t->getWeek() > 6 ? weekString[0] : weekString[t->getWeek()]);
707 }
708};
709
710#endif
#define SENSORLIB_LOG_E(...)
@license MIT License
DateTimeFormat
Definition SensorRTC.h:38
@ DT_FMT_HMS
Definition SensorRTC.h:40
@ DT_FMT_YMD_HMS_WEEK
Definition SensorRTC.h:45
@ DT_FMT_YMD
Definition SensorRTC.h:41
@ DT_FMT_MDY
Definition SensorRTC.h:42
@ DT_FMT_YMD_HMS
Definition SensorRTC.h:44
@ DT_FMT_HM
Definition SensorRTC.h:39
@ DT_FMT_DMY
Definition SensorRTC.h:43
uint8_t getDay() const
Definition SensorRTC.h:199
uint8_t getMinute() const
Definition SensorRTC.h:201
uint8_t getHour() const
Definition SensorRTC.h:200
uint8_t getWeek() const
Definition SensorRTC.h:203
RTC_Alarm(void)
Definition SensorRTC.h:194
uint8_t getSecond() const
Definition SensorRTC.h:202
RTC_Alarm(uint8_t hour, uint8_t minute, uint8_t second, uint8_t day, uint8_t week)
Definition SensorRTC.h:195
RTC_DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint8_t week=0)
Definition SensorRTC.h:68
uint8_t getMinute() const
Definition SensorRTC.h:149
RTC_DateTime(const char *date, const char *time)
Definition SensorRTC.h:74
uint8_t getMonth() const
Definition SensorRTC.h:146
uint8_t getDay() const
Definition SensorRTC.h:147
uint16_t getYear() const
Definition SensorRTC.h:145
uint8_t getHour() const
Definition SensorRTC.h:148
uint8_t getWeek() const
Definition SensorRTC.h:151
bool operator==(RTC_DateTime d)
Definition SensorRTC.h:125
RTC_DateTime(struct tm info)
Definition SensorRTC.h:71
uint8_t getSecond() const
Definition SensorRTC.h:150
struct tm toUnixTime()
Definition SensorRTC.h:131
bool(*)(uint8_t addr, uint8_t reg, uint8_t *buf, size_t len, bool writeReg, bool isWrite) CustomCallback
virtual const char * getChipName()=0
Get the name of the RTC chip.
uint32_t getLeapYear(uint32_t year)
Determine whether a given year is a leap year.
Definition SensorRTC.h:536
uint32_t getDayOfWeek(uint32_t day, uint32_t month, uint32_t year)
Calculate the day of the week for a given date using Zeller's congruence.
Definition SensorRTC.h:483
virtual void setDateTime(RTC_DateTime datetime)=0
Set the date and time of the RTC using an RTC_DateTime object.
int hwClockWrite()
Write the current system time to the RTC clock chip.
Definition SensorRTC.h:456
void setDateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
Set the date and time of the RTC using individual values.
Definition SensorRTC.h:351
static uint8_t BCD2DEC(uint8_t val)
Convert a Binary Coded Decimal (BCD) number to a decimal number.
Definition SensorRTC.h:657
virtual void reset()
Reset the RTC.
Definition SensorRTC.h:316
uint8_t getDaysInMonth(uint8_t month, uint16_t year)
Get the number of days in a given month of a specific year, considering leap years.
Definition SensorRTC.h:552
void convertUtcToTimezone(int &year, int &month, int &day, int &hour, int &minute, int &second, int timezoneOffsetSeconds)
Convert UTC time represented by individual values to the time in the specified timezone.
Definition SensorRTC.h:601
const char * strftime(DateTimeFormat style=DT_FMT_YMD_HMS_WEEK)
Format the current date and time according to the specified style.
Definition SensorRTC.h:372
void convertUtcToTimezone(struct tm &utcTime, int timezoneOffsetSeconds)
Overloaded function to convert UTC time represented by a struct tm object to the time in the specifie...
Definition SensorRTC.h:633
uint16_t getNextYear(uint16_t curYear)
Get the next year based on the current year.
Definition SensorRTC.h:525
virtual bool begin(SensorCommCustom::CustomCallback callback)=0
Initialize the RTC device using a custom callback.
virtual RTC_DateTime getDateTime()=0
Get the current date and time from the RTC.
time_t hwClockRead(const timezone *tz=NULL)
Read the time from the RTC (Real-Time Clock) and write it to the system clock.
Definition SensorRTC.h:427
static uint8_t DEC2BCD(uint8_t val)
Convert a decimal number to a Binary Coded Decimal (BCD) number.
Definition SensorRTC.h:667
uint8_t getNextMonth(uint8_t curMonth)
Get the next month based on the current month.
Definition SensorRTC.h:514
void getDateTime(struct tm *info)
Retrieve the current date and time from the RTC (Real-Time Clock) and populate a struct tm object.
Definition SensorRTC.h:335