Skip to content

Commit a4bc90c

Browse files
authored
Merge pull request #10 from tannewt/struct_array
Introduce StructArray that can be used for repeated register
2 parents 2576221 + aaaf8ea commit a4bc90c

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

adafruit_register/i2c_struct_array.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
# THE SOFTWARE.
22+
# pylint: disable=too-few-public-methods
23+
24+
"""`i2c_struct_array` - Array of structured registers based on `struct`
25+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
26+
"""
27+
28+
try:
29+
import struct
30+
except ImportError:
31+
import ustruct as struct
32+
33+
__version__ = "0.0.0-auto.0"
34+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Register.git"
35+
36+
class _BoundStructArray:
37+
"""
38+
Array object that `StructArray` constructs on demand.
39+
40+
:param object obj: The device object to bind to. It must have a `i2c_device` attribute
41+
:param int register_address: The register address to read the bit from
42+
:param type struct_format: The struct format string for each register element
43+
:param int count: Number of elements in the array
44+
"""
45+
def __init__(self, obj, register_address, struct_format, count):
46+
self.format = struct_format
47+
self.first_register = register_address
48+
self.obj = obj
49+
self.count = count
50+
51+
def _get_buffer(self, index):
52+
"""Shared bounds checking and buffer creation."""
53+
if not 0 <= index < self.count:
54+
raise IndexError()
55+
size = struct.calcsize(self.format)
56+
# We create the buffer every time instead of keeping the buffer (which is 32 bytes at least)
57+
# around forever.
58+
buf = bytearray(size + 1)
59+
buf[0] = self.first_register + size * index
60+
return buf
61+
62+
def __getitem__(self, index):
63+
buf = self._get_buffer(index)
64+
with self.obj.i2c_device:
65+
self.obj.i2c_device.write(buf, end=1, stop=False)
66+
self.obj.i2c_device.readinto(buf, start=1)
67+
return struct.unpack_from(self.format, buf, offset=1)
68+
69+
def __setitem__(self, index, value):
70+
buf = self._get_buffer(index)
71+
struct.pack_into(self.format, buf, 1, *value)
72+
with self.obj.i2c_device:
73+
self.obj.i2c_device.write(buf)
74+
75+
def __len__(self):
76+
return self.count
77+
78+
class StructArray:
79+
"""
80+
Repeated array of structured registers that are readable and writeable.
81+
82+
Based on the index, values are offset by the size of the structure.
83+
84+
Values are tuples that map to the values in the defined struct. See struct
85+
module documentation for struct format string and its possible value types.
86+
87+
.. note:: This assumes the device addresses correspond to 8-bit bytes. This is not suitable for
88+
devices with registers of other widths such as 16-bit.
89+
90+
:param int register_address: The register address to begin reading the array from
91+
:param str struct_format: The struct format string for this register.
92+
:param int count: Number of elements in the array
93+
"""
94+
def __init__(self, register_address, struct_format, count):
95+
self.format = struct_format
96+
self.address = register_address
97+
self.count = count
98+
self.array_id = "_structarray{}".format(register_address)
99+
100+
def __get__(self, obj, objtype=None):
101+
# We actually can't handle the indexing ourself due to data descriptor limits. So, we return
102+
# an object that can instead. This object is bound to the object passed in here by its
103+
# initializer and then cached on the object itself. That way its lifetime is tied to the
104+
# lifetime of the object itself.
105+
if not hasattr(obj, self.array_id):
106+
setattr(obj, self.array_id,
107+
_BoundStructArray(obj, self.address, self.format, self.count))
108+
return getattr(obj, self.array_id)

0 commit comments

Comments
 (0)