init
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#include "hardware_rtc.hpp"
|
||||
#include <logger.hpp>
|
||||
|
||||
|
||||
HardwareRTC::HardwareRTC(TwoWire& wire): wire(wire), initialized(false) {}
|
||||
|
||||
HardwareRTC::~HardwareRTC() {}
|
||||
|
||||
void HardwareRTC::begin() {
|
||||
if(wire.getClock() == 0) {
|
||||
wire.begin();
|
||||
wire.setClock(100000); // Set to 100kHz
|
||||
}
|
||||
initialized = true;
|
||||
LOG_DEBUG("RTC initialized");
|
||||
setSystemTime(0);
|
||||
}
|
||||
|
||||
bool HardwareRTC::setTime(time_t unixTimestamp) {
|
||||
if (!initialized) {
|
||||
LOG_WARN("RTC not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use time_t, which on ESP32 is 64-bit and safe for this conversion
|
||||
time_t t = unixTimestamp;
|
||||
struct tm timeStruct;
|
||||
gmtime_r(&t, &timeStruct);
|
||||
|
||||
// Check if the year is within the DS1307's valid range (2000-2099)
|
||||
if (timeStruct.tm_year < 100 || timeStruct.tm_year > 199) {
|
||||
// Year is out of the 2000-2099 range that the DS1307 can store.
|
||||
LOG_ERROR("RTC setTime: Year %d is out of range (2000-2099)", timeStruct.tm_year + 1900);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = decToBcd(timeStruct.tm_sec);
|
||||
buffer[1] = decToBcd(timeStruct.tm_min);
|
||||
buffer[2] = decToBcd(timeStruct.tm_hour);
|
||||
buffer[3] = decToBcd(timeStruct.tm_wday + 1);
|
||||
buffer[4] = decToBcd(timeStruct.tm_mday);
|
||||
buffer[5] = decToBcd(timeStruct.tm_mon + 1);
|
||||
// The DS1307 only stores years 00-99. We handle this by taking the year since 2000.
|
||||
buffer[6] = decToBcd(timeStruct.tm_year - 100);
|
||||
|
||||
writeRegisters(buffer, 7);
|
||||
|
||||
// set system time to match RTC
|
||||
setSystemTime(0);
|
||||
|
||||
LOG_DEBUG("RTC setTime: %s", toDateString(unixTimestamp).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t HardwareRTC::getTime() {
|
||||
if (!initialized) return 0;
|
||||
|
||||
uint8_t buffer[7];
|
||||
readRegisters(buffer, 7);
|
||||
|
||||
struct tm timeStruct = {0}; // Important: Initialize the struct to zero
|
||||
timeStruct.tm_sec = bcdToDec(buffer[0] & 0x7F);
|
||||
timeStruct.tm_min = bcdToDec(buffer[1]);
|
||||
timeStruct.tm_hour = bcdToDec(buffer[2] & 0x3F);
|
||||
timeStruct.tm_wday = bcdToDec(buffer[3]) - 1;
|
||||
timeStruct.tm_mday = bcdToDec(buffer[4]);
|
||||
timeStruct.tm_mon = bcdToDec(buffer[5]) - 1;
|
||||
// Assume all 2-digit years from the RTC are in the 21st century (2000-2099)
|
||||
timeStruct.tm_year = bcdToDec(buffer[6]) + 100; // Years since 1900
|
||||
|
||||
// mktime converts a local time struct to a time_t.
|
||||
// Since the RTC stores time without timezone info, we treat it as UTC.
|
||||
// timegm is the correct function for this, but mktime is often used
|
||||
// on embedded systems with the timezone set to UTC.
|
||||
time_t t = mktime(&timeStruct);
|
||||
|
||||
LOG_DEBUG("RTC getTime: %s", toDateString(t).c_str());
|
||||
|
||||
// Cast the 64-bit time_t to uint64_t for the return type
|
||||
return static_cast<time_t>(t);
|
||||
}
|
||||
|
||||
void HardwareRTC::setSystemTime(int timezoneOffsetHours) {
|
||||
if (!initialized) {
|
||||
LOG_WARN("RTC not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint64_t unixTime = getTime();
|
||||
if (unixTime == 0) return;
|
||||
|
||||
unixTime += timezoneOffsetHours * 3600;
|
||||
|
||||
LOG_DEBUG("RTC setSystemTime: %s", toDateString(unixTime).c_str());
|
||||
|
||||
struct timeval tv;
|
||||
// The tv_sec field is of type time_t, which is 64-bit on ESP32
|
||||
tv.tv_sec = unixTime;
|
||||
tv.tv_usec = 0;
|
||||
settimeofday(&tv, NULL);
|
||||
}
|
||||
|
||||
|
||||
bool HardwareRTC::isRunning() {
|
||||
if (!initialized) return false;
|
||||
|
||||
uint8_t buffer[1];
|
||||
readRegisters(buffer, 1);
|
||||
return !(buffer[0] & 0x80); // CH bit is 0 when running
|
||||
}
|
||||
|
||||
void HardwareRTC::setTimezone(const char* timezone) {
|
||||
setenv("TZ", timezone, 1);
|
||||
tzset();
|
||||
}
|
||||
|
||||
void HardwareRTC::update()
|
||||
{
|
||||
static uint32_t nextSync = 0;
|
||||
time_t now = millis();
|
||||
if (now >= nextSync) {
|
||||
if(!isRunning()) {
|
||||
LOG_WARN("RTC is not running, skipping update");
|
||||
return;
|
||||
}
|
||||
setSystemTime(0);
|
||||
nextSync = now + (15UL * 60UL * 1000UL); // every 15 minutes
|
||||
LOG_DEBUG("RTC update: System time synchronized with RTC");
|
||||
}
|
||||
}
|
||||
|
||||
String HardwareRTC::toDateString(time_t timestamp) {
|
||||
struct tm* timeinfo = gmtime(×tamp);
|
||||
char buffer[40];
|
||||
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
uint8_t HardwareRTC::bcdToDec(uint8_t bcd) {
|
||||
return ((bcd >> 4) * 10) + (bcd & 0x0F);
|
||||
}
|
||||
|
||||
uint8_t HardwareRTC::decToBcd(uint8_t dec) {
|
||||
return ((dec / 10) << 4) | (dec % 10);
|
||||
}
|
||||
|
||||
void HardwareRTC::readRegisters(uint8_t* buffer, uint8_t length) {
|
||||
Wire.beginTransmission(DS1307_ADDRESS);
|
||||
Wire.write(0x00); // start at register 0
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(DS1307_ADDRESS, length);
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
buffer[i] = Wire.read();
|
||||
}
|
||||
}
|
||||
|
||||
void HardwareRTC::writeRegisters(uint8_t* buffer, uint8_t length) {
|
||||
Wire.beginTransmission(DS1307_ADDRESS);
|
||||
Wire.write(0x00); // start at register 0
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
Wire.write(buffer[i]);
|
||||
}
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user