The interaction with the device is done via RWBits:
https://github.com/adafruit/Adafruit_Ci ... 2c_bits.py
If you look in the definition of _range, you can see it's an instance of RWBits:
Code: Select all
_range = RWBits(2, _LIS3MDL_CTRL_REG2, 5)
Now, if we look at the
__get__ and
__set__ methods for RWBits, we can see it accessing the I2C bus:
Code: Select all
def __get__(self, obj, objtype=None):
with obj.i2c_device as i2c:
i2c.write_then_readinto(self.buffer, self.buffer, out_end=1, in_start=1)
# read the number of bytes into a single variable
reg = 0
order = range(len(self.buffer) - 1, 0, -1)
if not self.lsb_first:
order = reversed(order)
for i in order:
reg = (reg << 8) | self.buffer[i]
reg = (reg & self.bit_mask) >> self.lowest_bit
# If the value is signed and negative, convert it
if reg & self.sign_bit:
reg -= 2 * self.sign_bit
return reg
def __set__(self, obj, value):
value <<= self.lowest_bit # shift the value over to the right spot
with obj.i2c_device as i2c:
i2c.write_then_readinto(self.buffer, self.buffer, out_end=1, in_start=1)
reg = 0
order = range(len(self.buffer) - 1, 0, -1)
if not self.lsb_first:
order = range(1, len(self.buffer))
for i in order:
reg = (reg << 8) | self.buffer[i]
# print("old reg: ", hex(reg))
reg &= ~self.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):
self.buffer[i] = reg & 0xFF
reg >>= 8
i2c.write(self.buffer)
RWBits is what's called a descriptor in Python:
Descriptors let objects customize attribute lookup, storage, and deletion.
See
https://docs.python.org/3/howto/descriptor.html for more information.
Dave