Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add typing and other tweaks #11

Merged
merged 6 commits into from
Jan 24, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
84 changes: 63 additions & 21 deletions adafruit_24lc32.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@
import time
from micropython import const

try:
from typing import Optional, Union, Sequence
from digitalio import DigitalInOut
from busio import I2C
except ImportError:
pass

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_24LC32.git"

Expand All @@ -40,9 +47,19 @@
class EEPROM:
"""
Driver base for the EEPROM Breakout.

:param int max_size: The maximum size of the EEPROM
:param bool write_protect: Turns on/off initial write protection
:param DigitalInOut wp_pin: (Optional) Physical pin connected to the ``WP`` breakout pin.
Must be a ``DigitalInOut`` object.
"""

def __init__(self, max_size, write_protect=False, wp_pin=None):
def __init__(
self,
max_size: int,
write_protect: bool = False,
wp_pin: Optional[DigitalInOut] = None,
) -> None:
self._max_size = max_size
self._wp = write_protect
self._wraparound = False
Expand All @@ -55,35 +72,39 @@ def __init__(self, max_size, write_protect=False, wp_pin=None):
self._wp_pin = wp_pin

@property
def write_wraparound(self):
def write_wraparound(self) -> bool:
"""Determines if sequential writes will wrapaound highest memory address
(``len(EEPROM) - 1``) address. If ``False``, and a requested write will
extend beyond the maximum size, an exception is raised.
"""
return self._wraparound

@write_wraparound.setter
def write_wraparound(self, value):
if not value in (True, False):
def write_wraparound(self, value: bool) -> None:
if not isinstance(value, bool):
raise ValueError("Write wraparound must be 'True' or 'False'.")
self._wraparound = value

@property
def write_protected(self):
def write_protected(self) -> bool:
"""The status of write protection. Default value on initialization is
``False``.

When a ``WP`` pin is supplied during initialization, or using
``write_protect_pin``, the status is tied to that pin and enables
hardware-level protection.

When no ``WP`` pin is supplied, protection is only at the software
level in this library.
"""
return self._wp if self._wp_pin is None else self._wp_pin.value

def __len__(self):
def __len__(self) -> int:
"""The size of the current EEPROM chip. This is one more than the highest
address location that can be read or written to.

.. code-block:: python

eeprom = adafruit_24lc32.EEPROM_I2C()
# size returned by len()
len(eeprom)
Expand All @@ -92,9 +113,11 @@ def __len__(self):
"""
return self._max_size

def __getitem__(self, address):
def __getitem__(self, address: Union[int, slice]) -> bytearray:
"""Read the value at the given index, or values in a slice.

.. code-block:: python

# read single index
eeprom[0]
# read values 0 thru 9 with a slice
Expand Down Expand Up @@ -130,9 +153,13 @@ def __getitem__(self, address):

return read_buffer

def __setitem__(self, address, value):
def __setitem__(
self, address: Union[int, slice], value: Union[int, Sequence[int]]
) -> None:
"""Write the value at the given starting index.

.. code-block:: python

# write single index
eeprom[0] = 1
# write values 0 thru 4 with a list
Expand Down Expand Up @@ -176,43 +203,58 @@ def __setitem__(self, address, value):

self._write(address.start, value, self._wraparound)

def _read_address(self, address, read_buffer):
def _read_address(self, address: int, read_buffer: bytearray) -> bytearray:
# Implemented by subclass
raise NotImplementedError

def _write(self, start_address, data, wraparound):
def _write(
self, start_address: int, data: Union[int, Sequence[int]], wraparound: bool
) -> None:
# Implemened by subclass
raise NotImplementedError


class EEPROM_I2C(EEPROM):
"""I2C class for EEPROM.
:param: ~busio.I2C i2c_bus: The I2C bus the EEPROM is connected to.
:param: int address: I2C address of EEPROM. Default address is ``0x50``.
:param: bool write_protect: Turns on/off initial write protection.
Default is ``False``.
:param: wp_pin: (Optional) Physical pin connected to the ``WP`` breakout pin.
Must be a ``digitalio.DigitalInOut`` object.

:param ~busio.I2C i2c_bus: The I2C bus the EEPROM is connected to.
:param int address: I2C address of EEPROM. Default address is ``0x50``.
:param bool write_protect: Turns on/off initial write protection.
Default is ``False``.
:param wp_pin: (Optional) Physical pin connected to the ``WP`` breakout pin.
Must be a ``DigitalInOut`` object.
"""

# pylint: disable=too-many-arguments
def __init__(self, i2c_bus, address=0x50, write_protect=False, wp_pin=None):
def __init__(
self,
i2c_bus: I2C,
address: int = 0x50,
write_protect: bool = False,
wp_pin: Optional[DigitalInOut] = None,
) -> None:
from adafruit_bus_device.i2c_device import ( # pylint: disable=import-outside-toplevel
I2CDevice as i2cdev,
)

self._i2c = i2cdev(i2c_bus, address)
super().__init__(_MAX_SIZE_I2C, write_protect, wp_pin)

def _read_address(self, address, read_buffer):
def _read_address(self, address: int, read_buffer: bytearray) -> bytearray:
write_buffer = bytearray(2)
write_buffer[0] = address >> 8
write_buffer[1] = address & 0xFF
with self._i2c as i2c:
i2c.write_then_readinto(write_buffer, read_buffer)
return read_buffer

def _write(self, start_address, data, wraparound=False):
def _write(
self,
start_address: int,
data: Union[int, Sequence[int]],
wraparound: bool = False,
) -> None:

# Decided against using the chip's "Page Write", since that would require
# doubling the memory usage by creating a buffer that includes the passed
# in data so that it can be sent all in one `i2c.write`. The single-write
Expand Down Expand Up @@ -248,8 +290,8 @@ def _write(self, start_address, data, wraparound=False):

# pylint: disable=no-member
@EEPROM.write_protected.setter
def write_protected(self, value):
if value not in (True, False):
def write_protected(self, value: bool) -> None:
if not isinstance(value, bool):
raise ValueError("Write protected value must be 'True' or 'False'.")
self._wp = value
if not self._wp_pin is None:
Expand Down