diff --git a/micropython/register/i2c_register.py b/micropython/register/i2c_register.py new file mode 100644 index 000000000..cea18fd46 --- /dev/null +++ b/micropython/register/i2c_register.py @@ -0,0 +1,931 @@ +""" + * Author(s): SquirtleSquadLeader + + * License: MIT + + * Purpose: + * The purpose of this module is to provide easy I2C Register + * access. It is inspired by the CircuitPython Register + * module maintained by Adafruit. + + * RORegBit - Single bit Read Only + * RWRegBit - Single bit Read/Write + + * RORegBits - Multi-bit Read Only + * RWRegBits - Multi-bit Read/Write + + * ROReg - Single/Multi Read Only + * RWReg - Single/Multi Read/Write + + + * Notes: + 1) Reference format strings below: + Format C Type Standard size + c char 1 + b signed char 1 + B unsigned char 1 + h short 2 + H unsigned short 2 + i integer 4 + I unsigned int 4 + l long 4 + L unsigned long 4 + q long long 8 + Q unsigned long long 8 + f float 4 + d double 8 +""" + +from machine import I2C +from struct import pack, unpack + + +class RORegBit: + def __init__(self, i2c, dev_addr, reg_addr, num_bytes, bit_location, endian="", fmt="B"): + """ + Creates an :class:`RORegBit` object which allows read only access to a single bit within a register. + + + :param i2c: I2C bus which connects the host system to the peripheral device + :type kind: machine.I2C() + :param dev_addr: I2C address of the device which + :type dev_addr: int() + :param reg_addr: Physical register address which contains the bit of interest + :type reg_addr: int() + :param num_bytes: Number of bytes to read + :type num_bytes: int() + :param bit_location: Location of bit within bitfield + :type bit_locatin: int() + :param endian: Endian-ness of system for which the code is intended to run on. str('') uses native Endian-ness. + :type endian: str() + :param fmt: Format code which is used to unpack data from bytes(). Defaults to 'B' which is good for a single 8-bit register + :type fmt: int() + + :return: An initialized RORegBit object + :rtype: RORegBit() + + + **Quickstart: Importing and using the device** + + Here is an example of using the :class:`RORegBit` class. + First you will need to import the following libraries: + + .. code-block:: python + + from machine import I2C + from register.register import RORegBit + + Once this is done you must define a :class:`machine.I2C` object and then pass that + to the :class:`RORegBit` object to instantiate it. + + .. code-block:: python + + i2c = I2C(0) # I2C details are project specific + + my_reg = RORegBit(i2c, 68, 5, 1, 5) + + 'my_reg' can now provide access to the :method:`__get__(). Using this method + will return the value of the bit found at :param bit_location:. + + .. code-block:: python + + value = my_reg.__get__() # 0 or 1 + + Alternatively, a :class:`RORegBit` object(s) can be placed within another class. + + .. code-block:: python + # import + from machine import I2C + from register.register import RORegBit + + # define I2C + i2c = I2C(0) + + # create class with desired functionality + class FooDevice: + + def __init__(self, i2c_bus): + self._my_reg_1 = RORegBit(i2c_bus, 68, 5, 1, 5) + self._my_reg_2 = RORegBit(i2c_bus, 68, 6, 1, 5) + + def get_my_reg1(self): + return self._my_reg_1.__get__() + + def get_my_reg2(self): + return self._my_reg_1.__get__() + + # invoke class object + device = FooDevice(i2c) + """ + + self._i2c = i2c + self._dev_addr = dev_addr + self._reg_addr = reg_addr + self._num_bytes = num_bytes + self._bit_location = bit_location + self._endian = endian + self._fmt = fmt + + __check_reg(self) + + del (i2c, dev_addr, reg_addr, num_bytes, bit_location, fmt) + + def __get__(self): + """ + :return: Returns the value of the bit located at :param bit_location: + :rtype: int() + """ + return __getbit(self) + + +class RWRegBit: + def __init__(self, i2c, dev_addr, reg_addr, num_bytes, bit_location, endian="", fmt="B"): + """ + Creates an :class:`RORegBit` object which allows read and write access to a single bit within a register. + + :param i2c: I2C bus which connects the host system to the peripheral device + :type kind: machine.I2C() + :param dev_addr: I2C address of the device which + :type dev_addr: int() + :param reg_addr: Physical register address which contains the bit of interest + :type reg_addr: int() + :param num_bytes: Number of bytes to read + :type num_bytes: int() + :param bit_location: Location of bit within bitfield + :type bit_locatin: int() + :param endian: Endian-ness of system for which the code is intended to run on. str('') uses native Endian-ness. + :type endian: str() + :param fmt: Format code which is used to unpack data from bytes(). Defaults to 'B' which is good for a single 8-bit register + :type fmt: int() + + :return: An initialized RWRegBit object + :rtype: RWRegBit() + + + **Quickstart: Importing and using the device** + + Here is an example of using the :class:`RWRegBit` class. + First you will need to import the following libraries: + + .. code-block:: python + + from machine import I2C + from register.register import RWRegBit + + Once this is done you must define a :class:`machine.I2C` object and then pass that + to the :class:`RWRegBit` object to instantiate it. + + .. code-block:: python + + i2c = I2C(0) # I2C details are project specific + + my_reg = RWRegBit(i2c, 68, 5, 1, 5) + + 'my_reg' can now provide access to the :method:`__get__() and :method:`__set__(). + Using these methods will get/set the value of the bit found at :param bit_location:. + + .. code-block:: python + my_reg.__set__(1) + + print(my_reg.__get__()) # prints 1 + + Alternatively, a :class:`RWRegBit` object(s) can be placed within another class. + + .. code-block:: python + # import + from machine import I2C + from register.register import RWRegBit + + # define I2C + i2c = I2C(0) + + # create class with desired functionality + class FooDevice: + + def __init__(self, i2c_bus): + self._my_reg = RORegBit(i2c_bus, 68, 5, 1, 5) + + def get_my_reg(self): + return self._my_reg.__get__() + + def get_my_reg2(self, n): + return self._my_reg.__set__(n) + + # invoke class object + device = FooDevice(i2c) + """ + self._i2c = i2c + self._dev_addr = dev_addr + self._reg_addr = reg_addr + self._num_bytes = num_bytes + self._bit_location = bit_location + self._endian = endian + self._fmt = fmt + + __check_reg(self) + + self._premask, self._postmask = __calc_mask(bit_location, bit_location, num_bytes) + + del (i2c, dev_addr, reg_addr, num_bytes, bit_location, endian, fmt) + + def __get__(self): + """ + :return: Returns the value of the bit located at :param bit_location: + :rtype: int() + """ + return __getbit(self) + + def __set__(self, setting): + """ + :return: Returns 'True' if operation successful + :rtype: bool() + """ + return __setbit(self, setting) + + +class RORegBits: + def __init__(self, i2c, dev_addr, reg_addr, num_bytes, lsb, msb, endian="", fmt="B"): + """ + Creates an :class:`RORegBits` object which allows read only access to a sequential set of bits within a bitfield. + + :param i2c: I2C bus which connects the host system to the peripheral device + :type kind: machine.I2C() + :param dev_addr: I2C address of the device which + :type dev_addr: int() + :param reg_addr: Physical register address which contains the bit of interest + :type reg_addr: int() + :param num_bytes: Number of bytes to read + :type num_bytes: int() + :param lsb: Location of least significant bit within bitfield + :type lsb: int() + :param msb: Location of most significant bit within bitfield + :type msb: int() + :param endian: Endian-ness of system for which the code is intended to run on. str('') uses native Endian-ness. + :type endian: str() + :param fmt: Format code which is used to unpack data from bytes(). Defaults to 'B' which is good for a single 8-bit register + :type fmt: int() + + :return: An initialized RORegBits object + :rtype: RORegBits() + + + **Quickstart: Importing and using the device** + + Here is an example of using the :class:`RORegBits` class. + First you will need to import the following libraries: + + .. code-block:: python + + from machine import I2C + from register.register import RORegBits + + Once this is done you must define a :class:`machine.I2C` object and then pass that + to the :class:`RORegBits` object to instantiate it. + + .. code-block:: python + + i2c = I2C(0) # I2C details are project specific + + my_reg = RORegBits(i2c_bus, 68, 5, 1, 0, 2) + + 'my_reg' can now provide access to the :method:`__get__(). Using this method + will return the value of the bit found at :param bit_location:. + + .. code-block:: python + + value = my_reg.__get__() # Returns some value from 0b000 to 0b111 + + Alternatively, a :class:`RORegBits` object(s) can be placed within another class. + + .. code-block:: python + # import + from machine import I2C + from register.register import RORegBits + + # define I2C + i2c = I2C(0) + + # create class with desired functionality + class FooDevice: + + def __init__(self, i2c_bus): + self._my_reg_1 = RORegBits(i2c_bus, 68, 5, 1, 0, 2) + self._my_reg_2 = RORegBits(i2c_bus, 68, 6, 1, 3, 6) + + def get_my_reg1(self): + return self._my_reg_1.__get__() + + @property + def my_reg2(self): + return self._my_reg_2.__get__() + + # invoke class object + device = FooDevice(i2c) + + n1 = device.get_my_reg() + n2 = device.my_reg2 + """ + self._i2c = i2c + self._dev_addr = dev_addr + self._reg_addr = reg_addr + self._num_bytes = num_bytes + self._endian = endian + self._fmt = fmt + + __check_reg(self) + + self._premask, self._mask, self._postmask = __calc_mask(lsb, msb, num_bytes) + + del (i2c, dev_addr, reg_addr, num_bytes, lsb, msb, endian, fmt) + + def __get__(self): + """ + :return: Returns the value of the bitfield located between :param lsb: and :param msb: + :rtype: int() + """ + return __getbits(self) + + +class RWRegBits: + def __init__(self, i2c, dev_addr, reg_addr, num_bytes, lsb, msb, endian="", fmt="B"): + """ + Creates an :class:`RWRegBits` object which allows read and write access to a sequential set of bits within a bitfield. + + :param i2c: I2C bus which connects the host system to the peripheral device + :type kind: machine.I2C() + :param dev_addr: I2C address of the device which + :type dev_addr: int() + :param reg_addr: Physical register address which contains the bit of interest + :type reg_addr: int() + :param num_bytes: Number of bytes to read + :type num_bytes: int() + :param lsb: Location of least significant bit within bitfield + :type lsb: int() + :param msb: Location of most significant bit within bitfield + :type msb: int() + :param endian: Endian-ness of system for which the code is intended to run on. str('') uses native Endian-ness. + :type endian: str() + :param fmt: Format code which is used to unpack data from bytes(). Defaults to 'B' which is good for a single 8-bit register + :type fmt: int() + + :return: An initialized RWRegBits object + :rtype: RWRegBits() + + + **Quickstart: Importing and using the device** + + Here is an example of using the :class:`RWRegBits` class. + First you will need to import the following libraries: + + .. code-block:: python + + from machine import I2C + from register.register import RWRegBits + + Once this is done you must define a :class:`machine.I2C` object and then pass that + to the :class:`RWRegBits` object to instantiate it. + + .. code-block:: python + + i2c = I2C(0) # I2C details are project specific + + my_reg = RWRegBits(i2c_bus, 68, 5, 1, 0, 2) + + 'my_reg' can now provide access to :method:`__get__() and :method:`__set__(). + + .. code-block:: python + + my_reg.__set__(0b110) # Returns some value from 0b000 to 0b111 + value = my_reg.__get__() # Returns 0b110, assuming nothing changes + + Alternatively, a :class:`RWRegBits` object(s) can be placed within another class. + + .. code-block:: python + # import + from machine import I2C + from register.register import RWRegBits + + # define I2C + i2c = I2C(0) + + # create class with desired functionality + class FooDevice: + + def __init__(self, i2c_bus): + self._my_reg_1 = RWRegBits(i2c_bus, 68, 5, 1, 0, 2) + self._my_reg_2 = RWRegBits(i2c_bus, 68, 6, 1, 3, 6) + + def get_my_reg1(self): + return self._my_reg_1.__get__() + + def set_my_reg1(self, n): + return self._my_reg_1.__set__(n) + + @property + def my_reg2(self): + return self._my_reg_2.__get__() + + @my_reg2.setter + def my_reg2(self, n): + return self._my_reg_2.__set__(n) + + # invoke class object + device = FooDevice(i2c) + + device.set_my_reg(0b110) + print(device.get_my_reg()) # prints 6 + + device.my_reg2 = 0b110 + print(device.my_reg2) # prints 6 + """ + self._i2c = i2c + self._dev_addr = dev_addr + self._reg_addr = reg_addr + self._num_bytes = num_bytes + self._endian = endian + self._fmt = fmt + + __check_reg(self) + + self._premask, self._mask, self._postmask = __calc_mask(lsb, msb, num_bytes) + + del (i2c, dev_addr, reg_addr, num_bytes, lsb, msb, fmt, endian) + + def __get__(self): + """ + :return: Returns the value of the bitfield located between :param lsb: and :param msb: + :rtype: int() + """ + return __getbits(self) + + def __set__(self, setting): + """ + :return: True if successful + :rtype: bool() + """ + return __setbits(self, setting) + + +class ROReg: + def __init__(self, i2c, dev_addr, reg_addr, num_bytes=1, endian="", fmt="B"): + """ + Creates a :class:`ROReg` object which allows read only access to n number of sequential registers, + where n is specified by :param num_bytes:. + + + :param i2c: I2C bus which connects the host system to the peripheral device + :type kind: machine.I2C() + :param dev_addr: I2C address of the device which + :type dev_addr: int() + :param reg_addr: Physical register address which contains the bit of interest + :type reg_addr: int() + :param num_bytes: Number of bytes to read. Defaults to 1. + :type num_bytes: int() + :param fmt: Format code which is used to unpack data from bytes(). Defaults to 'B'. + :type fmt: int() + + :return: An initialized ROReg object + :rtype: ROReg() + + + **Quickstart: Importing and using the device** + + Here is an example of using the :class:`ROReg` class. + First you will need to import the following libraries: + + .. code-block:: python + + from machine import I2C + from register.register import ROReg + + Once this is done you must define a :class:`machine.I2C` object and then pass that + to the :class:`ROReg` object to instantiate it. + + .. code-block:: python + + i2c = I2C(0) # I2C details are project specific + + my_reg = ROReg(i2c, 68, 5) + + 'my_reg' can now provide access to the :method:`__get__(). Using this method + will return the value of the bit found at :param bit_location:. + + .. code-block:: python + + value = my_reg.__get__() # some value between 0b0 and 0b1111_1111 + + Alternatively, a :class:`ROReg` object(s) can be placed within another class. + + .. code-block:: python + # import + from machine import I2C + from register.register import ROReg + + # define I2C + i2c = I2C(0) + + # create class with desired functionality + class FooDevice: + + def __init__(self, i2c_bus): + self._my_reg_1 = ROReg(i2c_bus, 68, 5) + self._my_reg_2 = ROReg(i2c_bus, 68, 6) + + def get_my_reg1(self): + return self._my_reg_1.__get__() + + @property + def my_reg2(self): + return self._my_reg_1.__get__() + + # invoke class object + device = FooDevice(i2c) + + print(device.get_my_reg1()) + print(device.my_reg2) + """ + self._i2c = i2c + self._dev_addr = dev_addr + self._reg_addr = reg_addr + self._num_bytes = num_bytes + self._fmt = fmt + self._endian = endian + + __check_reg(self) + + del (i2c, dev_addr, reg_addr, num_bytes, fmt, endian) + + def __get__(self): + """ + :return: Returns tuple containing n number of elements, where n is the number of characters in :param fmt: + :rtype: tuple() + """ + return __getreg(self) + + +class RWReg: + def __init__(self, i2c, dev_addr, reg_addr, num_bytes, endian="", fmt="B"): + """ + Creates a :class:`RWReg` object which allows read and write access to n number of sequential registers, + where n is specified by :param num_bytes:. + + :param i2c: I2C bus which connects the host system to the peripheral device + :type kind: machine.I2C() + :param dev_addr: I2C address of the device which + :type dev_addr: int() + :param reg_addr: Physical register address which contains the bit of interest + :type reg_addr: int() + :param num_bytes: Number of bytes to read. Defaults to 1. + :type num_bytes: int() + :param fmt: Format code which is used to unpack data from bytes(). Defaults to 'B'. + :type fmt: int() + + :return: An initialized RWReg object + :rtype: RWReg() + + + **Quickstart: Importing and using the device** + + Here is an example of using the :class:`RWReg` class. + First you will need to import the following libraries: + + .. code-block:: python + + from machine import I2C + from register.register import RWReg + + Once this is done you must define a :class:`machine.I2C` object and then pass that + to the :class:`RWReg` object to instantiate it. + + .. code-block:: python + + i2c = I2C(0) # I2C details are project specific + + my_reg = RWReg(i2c, 68, 5) + + 'my_reg' can now provide access to the :method:`__get__() and __set__(). + + .. code-block:: python + my_reg.__set__(0b0) + value = my_reg.__get__() # 0b0 if nothing changed + + Alternatively, a :class:`RWReg` object(s) can be placed within another class. + + .. code-block:: python + # import + from machine import I2C + from register.register import RWReg + + # define I2C + i2c = I2C(0) + + # create class with desired functionality + class FooDevice: + + def __init__(self, i2c_bus): + self._my_reg_1 = RWReg(i2c_bus, 68, 5) + self._my_reg_2 = RWReg(i2c_bus, 68, 6) + + def get_my_reg1(self): + return self._my_reg_1.__get__() + + def set_my_reg1(self, n): + return self._my_reg_1.__set__(n) + + @property + def my_reg2(self): + return self._my_reg_1.__get__() + + @my_reg2.setter + def my_reg2(self, n): + return self._my_reg_1.__set__(n) + + # invoke class object + device = FooDevice(i2c) + + device.set_my_reg1(0b110) + print(device.get_my_reg1()) # prints 6, assuming nothing changed + + device.my_reg2 = 0b1111_0000 + print(device.my_reg2) # prints 240 + """ + self._i2c = i2c + self._dev_addr = dev_addr + self._reg_addr = reg_addr + self._num_bytes = num_bytes + self._fmt = fmt + self._endian = endian + + __check_reg(self) + + del (i2c, dev_addr, reg_addr, num_bytes, fmt, endian) + + def __get__(self): + """ + :return: Returns tuple containing n number of elements, where n is the number of characters in :param fmt: + :rtype: tuple() + """ + return __getreg(self) + + def __set__(self, setting): + """ + :param setting: Value(s) to be written to register(s). Order must match :param fmt:. + :type setting: int(), bytes(), bytearray(), or list/tuple containing those values in order + :return: Returns True if operation successful + :rtype: tuple() + """ + return __setreg(self, setting) + + +""" +* +* GLOBAL HELPER FUNCTIONS +* +* +""" + + +def __getbit(reg_object): + if isinstance(reg_object, (RORegBit, RWRegBit)): + # Retrieve register value and unpack to int + value = reg_object._i2c.readfrom_mem( + reg_object._dev_addr, reg_object._reg_addr, reg_object._num_bytes + ) + + # Unpack byte + value = unpack(reg_object._endian + reg_object._fmt, value)[0] + + # Perform shift followed by _AND_ operation to determine bit state + return (value >> reg_object._bit_location) & 0b1 + + else: + raise TypeError("incorrect object type - must be RORegBit, RWRegBit") + + +def __setbit(reg_object, setting): + if isinstance(reg_object, RWRegBit): + if setting in (0, 1): + # Retrieve register value and unpack to int + value = reg_object._i2c.readfrom_mem( + reg_object._dev_addr, reg_object._reg_addr, reg_object._num_bytes + ) + + # Unpack byte + value = unpack(reg_object._endian + reg_object._fmt, value)[0] + + # Assemble byte + value = ( + (value & reg_object._postmask) + + (setting << reg_object._bit_location) + + (value & reg_object._premask) + ) + + # Pack to bytes + value = pack(reg_object._endian + reg_object._fmt, value) + + # Write to I2C + reg_object._i2c.writeto_mem(reg_object._dev_addr, reg_object._reg_addr, value) + + # Return True for success + return True + + else: + raise ValueError("setting must be int(0) or int(1)") + else: + raise TypeError("incorrect object type - must be RWRegBit") + + +def __getbits(reg_object): + if isinstance(reg_object, (RORegBits, RWRegBits)): + # Retrieve register value and unpack to int + value = reg_object._i2c.readfrom_mem( + reg_object._dev_addr, reg_object._reg_addr, reg_object._num_bytes + ) + + # Unpack bytes + value = unpack(reg_object._endian + reg_object._fmt, value)[0] + + # Return value of bit field + return (value & reg_object._mask) >> reg_object._lsb + + else: + raise TypeError("incorrect object type - must be RORegBits, RWRegBits") + + +def __setbits(reg_object, setting): + if isinstance(reg_object, RWRegBits): + if isinstance(setting, int) and setting <= reg_object._mask: + # Retrieve register value and unpack to int + value = reg_object._i2c.readfrom_mem( + reg_object._dev_addr, reg_object._reg_addr, reg_object._num_bytes + ) + + # Unpack bytes + value = unpack(reg_object._endian + reg_object._fmt, value)[0] + + # Assemble + value = ( + (value & reg_object._postmask) + + (setting << reg_object._lsb) + + (value & reg_object._premask) + ) + + # Pack to bytes object + value = struct.pack(reg_object._endian + reg_object._fmt, value) + + # Write to device + reg_object._i2c.writeto_mem(reg_object._dev_addr, reg_object._reg_addr, value) + + return True + + else: + raise ValueError(f"value of setting exceeds max value of bitfield: {reg_object._mask}") + else: + raise TypeError("incorrect object type - must be RWRegBits") + + +def __getreg(reg_object): + if isinstance(reg_object, (ROReg, RWReg)): + # Retrieve register value and unpack to int + values = reg_object._i2c.readfrom_mem( + reg_object._dev_addr, reg_object._reg_addr, reg_object._num_bytes + ) + + # Return Tuple of values + return unpack(reg_object._endian + reg_object._fmt, values) + + else: + raise TypeError("incorrect object type - must be ROReg, RWReg") + + +def __setreg(reg_object, settings): + if isinstance(reg_object, RWReg): + if isinstance(settings, (bytes, bytearray)): + # Write to device + reg_object._i2c.writeto_mem(reg_object._dev_addr, reg_object._reg_addr, settings) + + elif isinstance(settings, (tuple, list)): + # Where our data will go + d = bytearray() + + # Pack and append to d + for n in range(0, len(settings)): + d.extend(pack(reg_object._endian + reg_object._fmt[n], settings[n])) + + # Write to device + reg_object._i2c.writeto_mem(reg_object._dev_addr, reg_object._reg_addr, d) + + # Assumed single int() for single reg-op + elif isinstance(settings, int): + d = pack(reg_object._endian + reg_object._fmt, settings) + reg_object._i2c.writeto_mem(reg_object._dev_addr, reg_object._reg_addr, d) + + else: + raise TypeError( + "unsupported object type, settings must be int(), bytes(), bytearray(), tuple(), or list()" + ) + else: + raise TypeError("incorrect object type - must be ROReg, RWReg") + + +def __calc_mask(lsb, msb, numbytes): + """ + Takes in full description of bitfield that needs masking + + returns ints() pre, mask, post + """ + + # Check input types + if lsb.__class__() == int() and lsb >= 0: + if msb.__class__() == int() and msb >= 0: + if numbytes.__class__() == int() and numbytes >= 0: + # Check for detectable errors + if msb >= lsb: + # Single bit mask + if msb == lsb: + pre, post = 0b0, 0b0 + + # Calc post masking + for bit in range(msb + 1, numbytes * 8): + post = (post << 1) + 0b1 + + # Calc pre masking + for bit in range(0, lsb): + pre = (pre << 1) + 0b1 + + return pre, post + + # Multibit mask + else: + # Values to return + pre, mask, post = 0b0, 0b0, 0b0 + + # Calc post masking + for bit in range(msb + 1, numbytes * 8): + post = (post << 1) + 0b1 + + # Calc bitfield masking + for bit in range(lsb, msb + 1): + mask = (mask << 1) + 0b1 + + # No bits lower than 0 + if lsb == 0: + return 0b0, mask, post + + else: + for bit in range(0, lsb): + pre = (pre << 1) + 0b1 + + return pre, mask, post + else: + raise ValueError("msb must be greater than or equal to lsb") + else: + raise ValueError("numbytes must be of type int() and 0 or greater") + else: + raise ValueError("msb must be of type int() and 0 or greater") + else: + raise ValueError("lsb must be of type int() and 0 or greater") + + +def __check_reg(reg_object): + # Alowable struct.pack/unpack formats to check for + fmts = { + "b": 1, + "B": 1, + "h": 2, + "H": 2, + "f": 4, + "i": 4, + "I": 4, + "l": 4, + "L": 4, + "q": 8, + "Q": 8, + } + endians = "@><" + byte_count = 0 + + # Take in only register objects + if isinstance(reg_object, (RORegBit, RWRegBit, RORegBits, RWRegBits, ROReg, RWReg)): + # Make sure they are strings + if type(reg_object._fmt) == str and type(reg_object._endian) == str: + # Check each letter in format string, To see if allowable + for n in range(0, len(reg_object._fmt)): + if reg_object._fmt[n] in fmts: + # Add corresonding byte length to verify _num_bytes and format string agree + byte_count = byte_count + fmts[reg_object._fmt[n]] + + else: + raise ValueError(f"unsupported format code of '{reg_object._fmt[n]}'") + + if byte_count != reg_object._num_bytes: + raise ValueError( + f"format string accounts for {byte_count} bytes, _num_bytes value of {reg_object._num_bytes} does not match" + ) + + else: + raise TypeError("format and endian must be of type str()") + else: + raise TypeError( + "incorrect object type - must be ROReg, RWReg, ROBits, RWBits, ROReg, RWReg" + ) diff --git a/micropython/register/manifest.py b/micropython/register/manifest.py new file mode 100644 index 000000000..67ec04c5e --- /dev/null +++ b/micropython/register/manifest.py @@ -0,0 +1,7 @@ +metadata( + description="I2C register library for MicroPython.", + version="0.0.1", + pypi_publish="micropython-i2c_reg", +) + +require("struct")