#include "PCF85063_Driver.h" #include #include namespace drivers { PCF85063::PCF85063(I2C &i2c, const uint8_t address, const uint8_t ctrl1, const uint8_t ctrl2) : m_i2c(i2c), m_address(address) { bool success(true); if (ctrl1 == RTC_CTRL_1_DEFAULT) { const uint8_t def_conf1 = RTC_CTRL_1_DEFAULT | RTC_CTRL_1_CAP_SEL; // 12.5pF cap and 24h format success &= m_i2c.write(m_address, RTC_CTRL_1_ADDR, {def_conf1}); } if (ctrl2 == RTC_CTRL_2_DEFAULT) { const uint8_t def_conf2 = RTC_CTRL_2_DEFAULT | RTC_CTRL_2_MI; // enable 1 minute interrupt success &= m_i2c.write(m_address, RTC_CTRL_2_ADDR, {def_conf2}); } if (!success) LOG_ERROR("RTC Init Failure"); } const bool PCF85063::reset(void) { LOG_INFO("RTC Reset Initiated"); const uint8_t cfg = RTC_CTRL_1_DEFAULT | RTC_CTRL_1_CAP_SEL | RTC_CTRL_1_SR; if (m_i2c.write(m_address, RTC_CTRL_1_ADDR, {cfg})) return true; LOG_ERROR("RTC Reset Failure"); return false; } const bool PCF85063::setTime(const datetime_t time) { const std::vector buf = { decToBcd(time.second), decToBcd(time.minute), decToBcd(time.hour)}; if (m_i2c.write(m_address, RTC_SECOND_ADDR, buf)) return true; LOG_ERROR("RTC setTime failure"); return false; } const bool PCF85063::setDate(const datetime_t date) { const std::vector buf = { decToBcd(date.day), decToBcd(date.dotw), decToBcd(date.month), decToBcd(date.year - YEAR_OFFSET)}; if (m_i2c.write(m_address, RTC_DAY_ADDR, buf)) return true; LOG_ERROR("RTC setDate failure"); return false; } const bool PCF85063::setDatetime(const datetime_t datetime) { return setDate(datetime) && setTime(datetime); } const bool PCF85063::readDate(datetime_t &datetime) { std::vector buf; if (m_i2c.read(m_address, RTC_DAY_ADDR, 4, buf)) { datetime.day = bcdToDec(buf[0] & 0x3F); datetime.dotw = bcdToDec(buf[1] & 0x07); datetime.month = bcdToDec(buf[2] & 0x1F); datetime.year = bcdToDec(buf[3]) + YEAR_OFFSET; return true; } LOG_ERROR("RTC readDate Failure"); return false; } const bool PCF85063::readTime(datetime_t &datetime) { std::vector buf; if (m_i2c.read(m_address, RTC_SECOND_ADDR, 3, buf)) { datetime.second = bcdToDec(buf[0] & 0x7F); datetime.minute = bcdToDec(buf[1] & 0x7F); datetime.hour = bcdToDec(buf[2] & 0x3F); return true; } LOG_ERROR("RTC readTime Failure"); return false; } const bool PCF85063::readDatetime(datetime_t &datetime) { return readTime(datetime) && readDate(datetime); } const bool PCF85063::enableAlarm(const bool enable) { bool success(true); std::vector currStatus(1, RTC_CTRL_2_DEFAULT); success &= m_i2c.read(m_address, RTC_CTRL_2_ADDR, 1, currStatus); currStatus.at(0) &= ~RTC_CTRL_2_AF; // clear alarm flag if (enable) currStatus.at(0) |= RTC_CTRL_2_AIE; // enable alarm else currStatus.at(0) &= ~RTC_CTRL_2_AIE; // disable alarm if (m_i2c.write(m_address, RTC_CTRL_2_ADDR, currStatus)) return true; LOG_ERROR("RTC enableAlarm failure"); return false; } const bool PCF85063::setAlarm(datetime_t time) { const std::vector buf = { (uint8_t)(decToBcd(time.second) & (~RTC_ALARM)), (uint8_t)(decToBcd(time.minute) & (~RTC_ALARM)), (uint8_t)(decToBcd(time.hour) & (~RTC_ALARM)), (uint8_t)(RTC_ALARM), // disalbe day (uint8_t)(RTC_ALARM) // disalbe weekday }; if (m_i2c.write(m_address, RTC_SECOND_ALARM, buf)) return true; LOG_ERROR("RTC setAlarm failure"); return false; } const bool PCF85063::readAlarm(datetime_t &time) { std::vector buf; if (m_i2c.read(m_address, RTC_SECOND_ALARM, 5, buf)) { time.second = (uint8_t)bcdToDec(buf[0] & 0x7F); time.minute = (uint8_t)bcdToDec(buf[1] & 0x7F); time.hour = (uint8_t)bcdToDec(buf[2] & 0x3F); time.day = (uint8_t)bcdToDec(buf[3] & 0x3F); time.dotw = (uint8_t)bcdToDec(buf[4] & 0x07); return true; } LOG_ERROR("RTC readAlarm failure"); return false; } const bool PCF85063::getAlarmFlag(uint8_t &flags) { std::vector buf; if (m_i2c.read(m_address, RTC_CTRL_2_ADDR, 1, buf)) { flags = buf.at(0); return true; } LOG_ERROR("RTC readAlarmFlags failure"); return false; } const bool PCF85063::setOffset(const uint8_t ofst) { LOG_DEBUG("RTC set offset [", printHex(ofst).c_str(), "]"); return m_i2c.write(m_address, RTC_OFFSET_ADDR, {ofst}); } const uint8_t PCF85063::getOffset() { std::vector buf; if (m_i2c.read(m_address, RTC_OFFSET_ADDR, 1, buf)) { LOG_DEBUG("RTC get offset [", printHex(buf.front()).c_str(), "]"); return buf.front(); } return UINT8_MAX; } const std::string PCF85063::getTimeStr() { datetime_t dt; readDatetime(dt); return datetime2str(dt); } const PCF85063::datetime_t PCF85063::fromEpoch(const time_t currentTime) { PCF85063::datetime_t tm; struct tm *localTime = std::localtime(¤tTime); tm.year = localTime->tm_year + 1900; tm.month = localTime->tm_mon + 1; tm.day = localTime->tm_mday; tm.dotw = localTime->tm_wday; tm.hour = localTime->tm_hour; tm.minute = localTime->tm_min; tm.second = localTime->tm_sec; return tm; } const std::string PCF85063::datetime2str(const datetime_t &datetime) { tm dtime = datetime2tm(datetime); const std::string buf(std::asctime(&dtime)); return buf.substr(0, std::min(buf.find('\n'), buf.find('\r'))); } const std::string PCF85063::tm2str(const std::tm &datetime) { const std::string buf(std::asctime(&datetime)); return buf.substr(0, std::min(buf.find('\n'), buf.find('\r'))); } const std::tm PCF85063::datetime2tm(const datetime_t &datetime) { tm dtime; dtime.tm_sec = datetime.second; dtime.tm_min = datetime.minute; dtime.tm_hour = datetime.hour; dtime.tm_wday = datetime.dotw; dtime.tm_mday = datetime.day; dtime.tm_mon = datetime.month - 1; dtime.tm_year = datetime.year - 1900; // time offset in structure according cpp reference return dtime; } const uint8_t PCF85063::decToBcd(const int val) { return (uint8_t)((val / 10 * 16) + (val % 10)); } const int PCF85063::bcdToDec(uint8_t val) { return (const int)((val / 16 * 10) + (val % 16)); } }