forked from adafruit/Adafruit_CircuitPython_Register
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathregister_bits.py
More file actions
117 lines (90 loc) · 3.83 KB
/
register_bits.py
File metadata and controls
117 lines (90 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_register.register_bits`
====================================================
Multi bit registers
* Author(s): Tim Cocks
"""
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Register.git"
class RWBits:
"""
Multibit register that is readable and writeable.
Values are `int` between 0 and 2 ** ``num_bits`` - 1.
:param int num_bits: The number of bits in the field.
:param int register_address: The register address to read the bit from
: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 the bus the LSB? Defaults to true
:param bool signed: If True, the value is a "two's complement" signed value.
If False, it is unsigned.
"""
# pylint: disable=too-many-arguments
def __init__(
self,
num_bits: int,
register_address: int,
lowest_bit: int,
register_width: int = 1,
lsb_first: bool = True,
signed: bool = False,
):
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.address = register_address
self.buffer = bytearray(register_width)
self.lsb_first = lsb_first
self.sign_bit = (1 << (num_bits - 1)) if signed else 0
def __get__(self, obj, objtype=None):
# read data from register
obj.register_accessor.read_register(self.address, self.buffer)
# read the bytes into a single variable
reg = 0
order = range(len(self.buffer) - 1, -1, -1)
if not self.lsb_first:
order = reversed(order)
for i in order:
reg = (reg << 8) | self.buffer[i]
# extract integer value from specified bits
result = (reg & self.bit_mask) >> self.lowest_bit
# If the value is signed and negative, convert it
if result & self.sign_bit:
result -= 2 * self.sign_bit
return result
def __set__(self, obj, value):
# read current data from register
obj.register_accessor.read_register(self.address, self.buffer)
# shift in integer value to register data
reg = 0
order = range(len(self.buffer) - 1, -1, -1)
if not self.lsb_first:
order = reversed(order)
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 buffer to the register
obj.register_accessor.write_register(self.address, self.buffer)
class ROBits(RWBits):
"""
Multibit register that is read-only.
Values are `int` between 0 and 2 ** ``num_bits`` - 1.
:param int num_bits: The number of bits in the field.
:param int register_address: The register address to read the bit from
: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 the bus the LSB? Defaults to true
:param bool signed: If True, the value is a "two's complement" signed value.
If False, it is unsigned.
"""
def __set__(self, obj, value):
raise AttributeError()