Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
move read current value out of accessor into Bit(s). Support multibyt…
…e addresses. add some type annotations.
  • Loading branch information
FoamyGuy committed Sep 26, 2025
commit 519669623e1c5693937e3fc7e3bc0b6ef0fa4472
73 changes: 1 addition & 72 deletions adafruit_register/register_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,56 +62,15 @@ def read_register(self, buffer: bytearray):
def write_register(
self,
buffer: bytearray,
value: Union[int, bool],
lsb_first: bool,
bit_mask: int,
lowest_bit: int,
byte=None,
):
"""
Write register value over SPIDevice.

:param bytearray buffer: Buffer must have register address value at index 0.
Must be long enough to be read all data send by the device for specified register.
:param Union[int, bool] value: Value to write to the register.
:param bool lsb_first: Whether the least significant byte is first in multibyte registers.
:param int bit_mask: Bitmask of the bits where value will be written within the full data
of the register.
:param int lowest_bit: Index of the lowest bit in the full data of the register.
:param byte: Byte index within the full data of a multibyte register.
:return: None
"""
# read current register data
with self.spi_device as spi:
self._shift_rw_cmd_bit_into_address_byte(buffer, 1)
spi.write(buffer, end=1)
spi.readinto(buffer, start=1)

if isinstance(value, int):
# shift in integer value to register data
reg = 0
order = range(len(buffer) - 1, 0, -1)
if not lsb_first:
order = range(1, len(buffer))
for i in order:
reg = (reg << 8) | buffer[i]

shifted_value = value << lowest_bit
reg &= ~bit_mask # mask off the bits we're about to change
reg |= shifted_value # then or in our new value

# put data from reg back into buffer
for i in reversed(order):
buffer[i] = reg & 0xFF
reg >>= 8
elif isinstance(value, bool):
# shift in single bit value to register data
if value:
buffer[byte] |= bit_mask
else:
buffer[byte] &= ~bit_mask

# write updated register data
with self.spi_device as spi:
self._shift_rw_cmd_bit_into_address_byte(buffer, 0)
spi.write(buffer)
Expand Down Expand Up @@ -141,44 +100,14 @@ def read_register(self, buffer):
with self.i2c_device as i2c:
i2c.write_then_readinto(buffer, buffer, out_end=1, in_start=1)

def write_register(self, buffer, value, lsb_first, bit_mask, lowest_bit, byte=None):
def write_register(self, buffer):
"""
Write register value over I2CDevice.

:param bytearray buffer: Buffer must have register address value at index 0.
Must be long enough to be read all data send by the device for specified register.
:param Union[int, bool] value: Value to write to the register.
:param bool lsb_first: Whether the least significant byte is first in multibyte registers.
:param int bit_mask: Bitmask of the bits where value will be written within the full data
of the register.
:param int lowest_bit: Index of the lowest bit in the full data of the register.
:param byte: Byte index within the buffer where boolean value will be written into.
:return: None
"""

value <<= lowest_bit # shift the value over to the right spot
with self.i2c_device as i2c:
i2c.write_then_readinto(buffer, buffer, out_end=1, in_start=1)

if isinstance(value, int):
reg = 0
order = range(len(buffer) - 1, 0, -1)
if not lsb_first:
order = range(1, len(buffer))
for i in order:
reg = (reg << 8) | buffer[i]
# print("old reg: ", hex(reg))
reg &= ~bit_mask # mask off the bits we're about to change
reg |= value # then or in our new value
# print("new reg: ", hex(reg))
for i in reversed(order):
buffer[i] = reg & 0xFF
reg >>= 8

elif isinstance(value, bool):
if value:
buffer[byte] |= bit_mask
else:
buffer[byte] &= ~bit_mask

i2c.write(buffer)
49 changes: 40 additions & 9 deletions adafruit_register/register_bit.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,58 @@ class RWBit:

"""

def __init__(self, register_address, bit, register_width=1, lsb_first=True):
def __init__(
self,
register_address: int,
bit: int,
register_width: int = 1,
lsb_first: bool = True,
address_width: int = 1,
):
self.bit_mask = 1 << (bit % 8) # the bitmask *within* the byte!
self.buffer = bytearray(1 + register_width)

self.address = register_address
self.buffer[0] = register_address
self.buffer[1] = register_width - 1

self.address_width = address_width
self.buffer = bytearray(address_width + register_width)

# Pack possible multibyte address into the buffer
for i in range(address_width):
if lsb_first:
# Little-endian: least significant byte first
self.buffer[i] = (register_address >> (i * 8)) & 0xFF
else:
# Big-endian: most significant byte first
self.buffer[i] = (register_address >> ((address_width - 1 - i) * 8)) & 0xFF

self.lsb_first = lsb_first
self.bit_index = bit
if lsb_first:
self.byte = bit // 8 + 1 # the byte number within the buffer
self.byte = address_width + (bit // 8) # Little-endian: bit 0 in first register byte
else:
self.byte = register_width - (bit // 8) # the byte number within the buffer
self.byte = (
address_width + register_width - 1 - (bit // 8)
) # Big-endian: bit 0 in last register byte

def __get__(self, obj, objtype=None):
# read data from register
obj.register_accessor.read_register(self.buffer)

# check specified bit and return boolean
return bool(self.buffer[self.byte] & self.bit_mask)

def __set__(self, obj, value):
obj.register_accessor.write_register(
self.buffer, value, self.lsb_first, self.bit_mask, self.bit_index, byte=self.byte
)
# read current data from register
obj.register_accessor.read_register(self.buffer)

# update current data with new value
if value:
self.buffer[self.byte] |= self.bit_mask
else:
self.buffer[self.byte] &= ~self.bit_mask

# write updated data to register
obj.register_accessor.write_register(self.buffer)


class ROBit(RWBit):
Expand Down
56 changes: 44 additions & 12 deletions adafruit_register/register_bits.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,47 @@ class RWBits:
:param int lowest_bit: The lowest bits index within the byte at ``register_address``
:param int register_width: The number of bytes in the register. Defaults to 1.
:param bool lsb_first: Is the first byte we read from SPI the LSB? Defaults to true
:param int address_width: The width of the register address in bytes. Defaults to 1.
"""

# pylint: disable=too-many-arguments
def __init__(
self,
num_bits,
register_address,
lowest_bit,
register_width=1,
lsb_first=True,
num_bits: int,
register_address: int,
lowest_bit: int,
register_width: int = 1,
lsb_first: bool = True,
address_width: int = 1,
):
self.bit_mask = ((1 << num_bits) - 1) << lowest_bit

if self.bit_mask >= 1 << (register_width * 8):
raise ValueError("Cannot have more bits than register size")
self.lowest_bit = lowest_bit
self.buffer = bytearray(1 + register_width)
self.buffer[0] = register_address
self.buffer[1] = register_width - 1

self.address_width = address_width
self.buffer = bytearray(address_width + register_width)

# Pack possible multibyte address into the buffer
for i in range(address_width):
if lsb_first:
# Little-endian: least significant byte first
self.buffer[i] = (register_address >> (i * 8)) & 0xFF
else:
# Big-endian: most significant byte first
self.buffer[i] = (register_address >> ((address_width - 1 - i) * 8)) & 0xFF

# self.buffer[1] = register_width - 1
self.lsb_first = lsb_first

def __get__(self, obj, objtype=None):
# read data from register
obj.register_accessor.read_register(self.buffer)

# read the bytes into a single variable
reg = 0
order = range(len(self.buffer) - 1, 0, -1)
order = range(len(self.buffer) - 1, self.address_width - 1, -1)
if not self.lsb_first:
order = reversed(order)
for i in order:
Expand All @@ -64,9 +78,27 @@ def __get__(self, obj, objtype=None):
return result

def __set__(self, obj, value):
obj.register_accessor.write_register(
self.buffer, value, self.lsb_first, self.bit_mask, self.lowest_bit
)
# read current data from register
obj.register_accessor.read_register(self.buffer)

# shift in integer value to register data
reg = 0
order = range(len(self.buffer) - 1, self.address_width - 1, -1)
if not self.lsb_first:
order = range(1, len(self.buffer))
for i in order:
reg = (reg << 8) | self.buffer[i]
shifted_value = value << self.lowest_bit
reg &= ~self.bit_mask # mask off the bits we're about to change
reg |= shifted_value # then or in our new value

# put data from reg back into buffer
for i in reversed(order):
self.buffer[i] = reg & 0xFF
reg >>= 8

# write updated data into the register
obj.register_accessor.write_register(self.buffer)


class ROBits(RWBits):
Expand Down