diff options
Diffstat (limited to 'src/pico/adafruit_register/i2c_bcd_datetime.py')
| -rwxr-xr-x | src/pico/adafruit_register/i2c_bcd_datetime.py | 114 |
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) |