mirror of https://github.com/arendst/Tasmota.git
162 lines
5.2 KiB
C++
162 lines
5.2 KiB
C++
/*
|
|
xsns_96_pcf85363.ino - PCF85363 RTC chip support for Tasmota
|
|
|
|
SPDX-FileCopyrightText: 2022 Theo Arends
|
|
|
|
SPDX-License-Identifier: GPL-3.0-only
|
|
*/
|
|
|
|
#ifdef USE_I2C
|
|
#ifdef USE_PCF85363
|
|
/*********************************************************************************************\
|
|
* PCF85363 support
|
|
*
|
|
* I2C Address: 0x51
|
|
\*********************************************************************************************/
|
|
|
|
#define XSNS_96 96
|
|
#define XI2C_66 66 // See I2CDEVICES.md
|
|
|
|
#define USE_PCF85363_ADDR 0x51 // PCF85363 I2C Address
|
|
|
|
bool pcf85363_detected = false;
|
|
|
|
/*-------------------------------------------------------------------------------------------*\
|
|
* Read time and return the epoch time (second since 1-1-1970 00:00)
|
|
\*-------------------------------------------------------------------------------------------*/
|
|
uint32_t Pcf85363ReadTime(void) {
|
|
Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR);
|
|
Wire.write(0x00);
|
|
Wire.endTransmission();
|
|
|
|
uint8_t buffer[8];
|
|
Wire.requestFrom((int)USE_PCF85363_ADDR, (int)8);
|
|
for (uint32_t i = 0; i < 8; i++) { buffer[i] = Wire.read(); }
|
|
Wire.endTransmission();
|
|
|
|
TIME_T tm;
|
|
tm.second = Bcd2Dec(buffer[1] & 0x7F);
|
|
tm.minute = Bcd2Dec(buffer[2] & 0x7F);
|
|
tm.hour = Bcd2Dec(buffer[3]);
|
|
tm.day_of_month = Bcd2Dec(buffer[4]);
|
|
tm.day_of_week = buffer[5];
|
|
tm.month = Bcd2Dec(buffer[6]);
|
|
tm.year = 30 + Bcd2Dec(buffer[7]); // Offset from 1970. So 2022 - 1970 = 52
|
|
return MakeTime(tm);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------------------------*\
|
|
* Get time as TIME_T and set time to this value
|
|
\*-------------------------------------------------------------------------------------------*/
|
|
void Pcf85363SetTime(uint32_t epoch_time) {
|
|
TIME_T tm;
|
|
BreakTime(epoch_time, tm);
|
|
|
|
uint8_t buffer[8];
|
|
buffer[0] = 0x00; // 100th_seconds (not used)
|
|
buffer[1] = Dec2Bcd(tm.second);
|
|
buffer[2] = Dec2Bcd(tm.minute);
|
|
buffer[3] = Dec2Bcd(tm.hour);
|
|
buffer[4] = Dec2Bcd(tm.day_of_month);
|
|
buffer[5] = tm.day_of_week;
|
|
buffer[6] = Dec2Bcd(tm.month);
|
|
buffer[7] = Dec2Bcd(tm.year -30); // Offset from 1970
|
|
/*
|
|
// Handbook page 13
|
|
Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR);
|
|
Wire.write(0x2E);
|
|
Wire.write(0x01); // Set stop
|
|
Wire.write(0xA4); // Clear prescaler
|
|
for (uint32_t i = 0; i < 8; i++) { Wire.write(buffer[i]); }
|
|
Wire.endTransmission();
|
|
Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR);
|
|
Wire.write(0x2E);
|
|
Wire.write(0x00); // Set start
|
|
Wire.endTransmission();
|
|
*/
|
|
Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR);
|
|
Wire.write(0x00);
|
|
for (uint32_t i = 0; i < 8; i++) { Wire.write(buffer[i]); }
|
|
Wire.endTransmission();
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------------------------*\
|
|
* Dump all registers
|
|
\*-------------------------------------------------------------------------------------------*/
|
|
/*
|
|
void Pcf85363Dump(void) {
|
|
uint8_t buffer[64];
|
|
|
|
// 0x00 to 0x2F
|
|
Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR);
|
|
Wire.write(0x00);
|
|
Wire.endTransmission();
|
|
Wire.requestFrom((int)USE_PCF85363_ADDR, (int)48);
|
|
for (uint32_t i = 0; i < 48; i++) {
|
|
buffer[i] = Wire.read();
|
|
}
|
|
Wire.endTransmission();
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Read 0x00: %48_H"), buffer);
|
|
|
|
// 0x40 to 0x7F
|
|
Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR);
|
|
Wire.write(0x40);
|
|
Wire.endTransmission();
|
|
Wire.requestFrom((int)USE_PCF85363_ADDR, (int)64);
|
|
for (uint32_t i = 0; i < 64; i++) {
|
|
buffer[i] = Wire.read();
|
|
}
|
|
Wire.endTransmission();
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Read 0x40: %64_H"), buffer);
|
|
}
|
|
*/
|
|
/*********************************************************************************************/
|
|
|
|
void Pcf85363Detect(void) {
|
|
if (!I2cSetDevice(USE_PCF85363_ADDR)) { return; }
|
|
I2cSetActiveFound(USE_PCF85363_ADDR, "PCF85363");
|
|
|
|
pcf85363_detected = true;
|
|
|
|
if (Rtc.utc_time < START_VALID_TIME) { // Not sync with NTP/GPS (time not valid), so read time
|
|
uint32_t time = Pcf85363ReadTime(); // Read UTC TIME
|
|
if (time > START_VALID_TIME) {
|
|
Rtc.utc_time = time;
|
|
RtcSync("PCF85363");
|
|
}
|
|
}
|
|
}
|
|
|
|
void Pcf85363TimeSynced(void) {
|
|
if ((Rtc.utc_time > START_VALID_TIME) && // Valid UTC time
|
|
(abs((int32_t)(Rtc.utc_time - Pcf85363ReadTime())) > 2)) { // Time has drifted from RTC more than 2 seconds
|
|
Pcf85363SetTime(Rtc.utc_time); // Update time
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Re-synced (" D_UTC_TIME ") %s"), GetDateAndTime(DT_UTC).c_str());
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************************\
|
|
* Interface
|
|
\*********************************************************************************************/
|
|
|
|
bool Xsns96(uint8_t function) {
|
|
if (!I2cEnabled(XI2C_66)) { return false; }
|
|
|
|
bool result = false;
|
|
|
|
if (FUNC_INIT == function) {
|
|
Pcf85363Detect();
|
|
}
|
|
else if (pcf85363_detected) {
|
|
switch (function) {
|
|
case FUNC_TIME_SYNCED:
|
|
Pcf85363TimeSynced();
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endif // USE_PCF85363
|
|
#endif // USE_I2C
|