133 lines
4.3 KiB
Python
133 lines
4.3 KiB
Python
"""CircuitPython PCF85063 Real-Time Clock (RTC) driver.
|
|
|
|
Synchronizes the hardware RTC with CircuitPython's native rtc.RTC() system clock.
|
|
"""
|
|
|
|
import rtc
|
|
import time
|
|
|
|
class PCF85063:
|
|
ADDR = 0x51
|
|
TIME_REG_START = 0x04
|
|
|
|
def __init__(self, i2c):
|
|
self.i2c = i2c
|
|
self._init_rtc()
|
|
|
|
def read_reg(self, reg, n=1):
|
|
while not self.i2c.try_lock():
|
|
pass
|
|
try:
|
|
self.i2c.writeto(self.ADDR, bytes([reg]))
|
|
buf = bytearray(n)
|
|
self.i2c.readfrom_into(self.ADDR, buf)
|
|
return buf
|
|
except Exception as e:
|
|
print(f"RTC read failed at reg 0x{reg:02X}: {e}")
|
|
return None
|
|
finally:
|
|
self.i2c.unlock()
|
|
|
|
def write_reg(self, reg, data):
|
|
while not self.i2c.try_lock():
|
|
pass
|
|
try:
|
|
payload = bytearray([reg])
|
|
if isinstance(data, (bytes, bytearray, list)):
|
|
payload.extend(data)
|
|
else:
|
|
payload.append(data)
|
|
self.i2c.writeto(self.ADDR, payload)
|
|
return True
|
|
except Exception as e:
|
|
print(f"RTC write failed at reg 0x{reg:02X}: {e}")
|
|
return False
|
|
finally:
|
|
self.i2c.unlock()
|
|
|
|
def _init_rtc(self):
|
|
ctrl1 = self.read_reg(0x00, 1)
|
|
if ctrl1 is not None and (ctrl1[0] & 0x20):
|
|
print("RTC oscillator was stopped. Starting oscillator...")
|
|
self.write_reg(0x00, 0x00)
|
|
|
|
def _dec2bcd(self, val):
|
|
return (val // 10 << 4) | (val % 10)
|
|
|
|
def _bcd2dec(self, val):
|
|
return ((val >> 4) * 10) + (val & 0x0F)
|
|
|
|
def get_datetime(self):
|
|
"""Reads current time from hardware RTC.
|
|
|
|
Returns:
|
|
tuple: (year, month, day, weekday, hour, minute, second) or None on error.
|
|
"""
|
|
data = self.read_reg(self.TIME_REG_START, 7)
|
|
if data is None:
|
|
return None
|
|
|
|
second = self._bcd2dec(data[0] & 0x7F)
|
|
minute = self._bcd2dec(data[1] & 0x7F)
|
|
hour = self._bcd2dec(data[2] & 0x3F)
|
|
day = self._bcd2dec(data[3] & 0x3F)
|
|
weekday = data[4] & 0x07
|
|
month = self._bcd2dec(data[5] & 0x1F)
|
|
year = 2000 + self._bcd2dec(data[6])
|
|
|
|
return (year, month, day, weekday, hour, minute, second)
|
|
|
|
def set_datetime(self, dt):
|
|
"""Sets the hardware RTC time.
|
|
|
|
Args:
|
|
dt (tuple): (year, month, day, weekday, hour, minute, second)
|
|
"""
|
|
try:
|
|
year, month, day, weekday, hour, minute, second = dt
|
|
reg_year = year % 100
|
|
|
|
data = bytearray(7)
|
|
data[0] = self._dec2bcd(second) & 0x7F
|
|
data[1] = self._dec2bcd(minute)
|
|
data[2] = self._dec2bcd(hour)
|
|
data[3] = self._dec2bcd(day)
|
|
data[4] = weekday & 0x07
|
|
data[5] = self._dec2bcd(month)
|
|
data[6] = self._dec2bcd(reg_year)
|
|
|
|
return self.write_reg(self.TIME_REG_START, data)
|
|
except Exception as e:
|
|
print(f"Error setting PCF85063 RTC: {e}")
|
|
return False
|
|
|
|
def sync_to_system(self):
|
|
"""Synchronizes the CircuitPython system time from the hardware RTC."""
|
|
dt = self.get_datetime()
|
|
if dt:
|
|
year, month, day, weekday, hour, minute, second = dt
|
|
r = rtc.RTC()
|
|
r.datetime = time.struct_time((year, month, day, hour, minute, second, weekday, -1, -1))
|
|
print(f"System clock synced to RTC: {year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}")
|
|
return True
|
|
return False
|
|
|
|
def sync_from_system(self):
|
|
"""Synchronizes the hardware RTC time from the system clock."""
|
|
try:
|
|
t = time.localtime()
|
|
dt = (t.tm_year, t.tm_mon, t.tm_mday, t.tm_wday, t.tm_hour, t.tm_min, t.tm_sec)
|
|
success = self.set_datetime(dt)
|
|
if success:
|
|
print(f"RTC synced from System: {t.tm_year:04d}-{t.tm_mon:02d}-{t.tm_mday:02d} {t.tm_hour:02d}:{t.tm_min:02d}:{t.tm_sec:02d}")
|
|
return success
|
|
except Exception as e:
|
|
print(f"Error syncing RTC from system: {e}")
|
|
return False
|
|
|
|
def get_time_string(self):
|
|
dt = self.get_datetime()
|
|
if dt:
|
|
return f"{dt[0]:04d}-{dt[1]:02d}-{dt[2]:02d} {dt[4]:02d}:{dt[5]:02d}:{dt[6]:02d}"
|
|
return "0000-00-00 00:00:00"
|