aboutsummaryrefslogtreecommitdiff
path: root/src/pico/adafruit_register/i2c_bcd_datetime.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/pico/adafruit_register/i2c_bcd_datetime.py')
-rwxr-xr-xsrc/pico/adafruit_register/i2c_bcd_datetime.py114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/pico/adafruit_register/i2c_bcd_datetime.py b/src/pico/adafruit_register/i2c_bcd_datetime.py
new file mode 100755
index 0000000..2bb458a
--- /dev/null
+++ b/src/pico/adafruit_register/i2c_bcd_datetime.py
@@ -0,0 +1,114 @@
+# SPDX-FileCopyrightText: 2016 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+# pylint: disable=too-few-public-methods
+
+"""
+`adafruit_register.i2c_bcd_datetime`
+====================================================
+
+Binary Coded Decimal date and time register
+
+* Author(s): Scott Shawcroft
+"""
+
+__version__ = "0.0.0+auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Register.git"
+
+import time
+
+try:
+ from typing import Optional, Type
+ from typing_extensions import Literal
+ from circuitpython_typing.device_drivers import I2CDeviceDriver
+except ImportError:
+ pass
+
+
+def _bcd2bin(value: int) -> int:
+ """Convert binary coded decimal to Binary
+
+ :param value: the BCD value to convert to binary (required, no default)
+ """
+ return value - 6 * (value >> 4)
+
+
+def _bin2bcd(value: int) -> int:
+ """Convert a binary value to binary coded decimal.
+
+ :param value: the binary value to convert to BCD. (required, no default)
+ """
+ return value + 6 * (value // 10)
+
+
+class BCDDateTimeRegister:
+ """
+ Date and time register using binary coded decimal structure.
+
+ The byte order of the register must* be: second, minute, hour, weekday, day (1-31), month, year
+ (in years after 2000).
+
+ * Setting weekday_first=False will flip the weekday/day order so that day comes first.
+
+ Values are `time.struct_time`
+
+ :param int register_address: The register address to start the read
+ :param bool weekday_first: True if weekday is in a lower register than the day of the month
+ (1-31)
+ :param int weekday_start: 0 or 1 depending on the RTC's representation of the first day of the
+ week
+ """
+
+ def __init__(
+ self,
+ register_address: int,
+ weekday_first: bool = True,
+ weekday_start: Literal[0, 1] = 1,
+ ) -> None:
+ self.buffer = bytearray(8)
+ self.buffer[0] = register_address
+ if weekday_first:
+ self.weekday_offset = 0
+ else:
+ self.weekday_offset = 1
+ self.weekday_start = weekday_start
+ # Masking value list n/a sec min hr day wkday mon year
+ self.mask_datetime = b"\xFF\x7F\x7F\x3F\x3F\x07\x1F\xFF"
+
+ def __get__(
+ self,
+ obj: Optional[I2CDeviceDriver],
+ objtype: Optional[Type[I2CDeviceDriver]] = None,
+ ) -> time.struct_time:
+ # Read and return the date and time.
+ with obj.i2c_device as i2c:
+ i2c.write_then_readinto(self.buffer, self.buffer, out_end=1, in_start=1)
+ return time.struct_time(
+ (
+ _bcd2bin(self.buffer[7] & self.mask_datetime[7]) + 2000,
+ _bcd2bin(self.buffer[6] & self.mask_datetime[6]),
+ _bcd2bin(self.buffer[5 - self.weekday_offset] & self.mask_datetime[4]),
+ _bcd2bin(self.buffer[3] & self.mask_datetime[3]),
+ _bcd2bin(self.buffer[2] & self.mask_datetime[2]),
+ _bcd2bin(self.buffer[1] & self.mask_datetime[1]),
+ _bcd2bin(
+ (self.buffer[4 + self.weekday_offset] & self.mask_datetime[5])
+ - self.weekday_start
+ ),
+ -1,
+ -1,
+ )
+ )
+
+ def __set__(self, obj: I2CDeviceDriver, value: time.struct_time) -> None:
+ self.buffer[1] = _bin2bcd(value.tm_sec) & 0x7F # format conversions
+ self.buffer[2] = _bin2bcd(value.tm_min)
+ self.buffer[3] = _bin2bcd(value.tm_hour)
+ self.buffer[4 + self.weekday_offset] = _bin2bcd(
+ value.tm_wday + self.weekday_start
+ )
+ self.buffer[5 - self.weekday_offset] = _bin2bcd(value.tm_mday)
+ self.buffer[6] = _bin2bcd(value.tm_mon)
+ self.buffer[7] = _bin2bcd(value.tm_year - 2000)
+ with obj.i2c_device:
+ obj.i2c_device.write(self.buffer)