Metadata-Version: 1.1
Name: py-i2c-register
Version: 0.0.3
Summary: Python wrapper library around the common I2C controller register pattern.
Home-page: https://github.com/Noah-Huppert/py-i2c-register
Author: Noah Huppert
Author-email: developer.noah@gmail.com
License: MIT
Description: Python I2C Register |Build Status| |Test Coverage|
        ==================================================
        
        Python wrapper library around the common I2C controller register
        pattern.
        
        I2C Register is a python library which aims to make communicating with
        registers on I2C devices dead simple. It is meant to directly transfer
        the Register Definitions pages of a data sheet into your program.
        
        Table Of Contents
        =================
        
        -  `Quick Example <#quick-example>`__
        -  `Systems Overview <#systems-overview>`__
        
           -  `Creating a RegisterList <#creating-a-registerlist>`__
           -  `Defining Registers <#defining-registers>`__
           -  `Adding RegisterSegments <#adding-registersegments>`__
           -  `Reading from RegisterSegments <#reading-from-registersegments>`__
           -  `Writing to RegisterSegments <#writing-to-registersegments>`__
        
        -  `Writting Wrapper Classes <#writing-wrapper-classes>`__
        -  `Development <#development>`__
        
           -  `Running Tests <#running-tests>`__
        
        Quick Example
        =============
        
        Take these control register definitions from a data sheet: |Example
        Hardware Data Sheet Register Definitions page 1| |Example Hardware Data
        Sheet Register Definitions page 2|
        
        With the help of the I2C Register library they can easily be represented
        and manipulated.
        
        .. code:: python
        
            # Create RegisterList instance to hold registers, device's i2c address is 0x62
            controls = RegisterList(0x62, i2c, {})
        
            # Add a definition for an ACQ_COMMAND (Acquisition Command) register, address 0x00 with WRITE permissions
            controls.add("ACQ_COMMAND", 0x00, Register.WRITE, {})\
                .add("ACQ_COMMAND", 0, 7, [0] * 8)  # Define the segment of bits to read with LSB index of 0 and MSB index of 7
                
            # Add a definition for a STATUS register, address 0x01 with READ permissions
            controls.add("STATUS", 0x01, Register.READ, {}) \
                # Define various individual Register Segments which each signify different parts of the status
                .add("PROC_ERROR_FLAG", 6, 6, [0]) \
                .add("HEALTH_FLAG", 5, 5, [0]) \
                .add("SECONDARY_RET_FLAG", 4, 4, [0]) \
                .add("INVALID_SIGNAL_FLAG", 3, 3, [0]) \
                .add("SIGNAL_OVERFLOW_FLAG", 2, 2, [0]) \
                .add("REFERENCE_OVERFLOW_FLAG", 1, 1, [0]) \
                .add("BUSY_FLAG", 0, 0, [0])
                
            # Add a definition for a VELOCITY register, address 0x09 with READ permissions
            controls.add("VELOCITY", 0x09, Register.READ, {})\
                .add("VELOCITY", 0, 7, [0] * 8)  # Define the segment of bits to read for velocity value with LSB index of 0 and MSB index of 7
        
                
            # Super simple to read and write values
            # Set ACQ_COMMAND Register bits to value of 0x04, then write to register
            controls.set_bits_from_int("ACQ_COMMAND", "ACQ_COMMAND", 0x04, write_after=True)  
        
            # Read STATUS register for BUSY_FLAG value and convert to an integer
            busy = controls.to_int("STATUS", "BUSY_FLAG", read_first=True)
        
            # Read VELOCITY register and convert to two's compliment integer
            velocity = controls.to_twos_comp_int("VELOCITY", "VELOCITY", read_first=True)
        
        Systems Overview
        ================
        
        The main class this library provides is the ``RegisterList`` class. This
        class manages a list of ``Register`` definitions. It also provides some
        useful helper methods to make performing certain common actions quick
        and easy.
        
        Creating a RegisterList
        -----------------------
        
        To create a ``RegisterList`` import the ``register_list.RegisterList``
        class. Then call the constructor giving it a I2C device address, an `I2C
        Object </docs/i2c-object.md>`__, and any ``Register``\ s you have
        already defined:
        
        .. code:: python
        
            from py_i2c_register.register_list import RegisterList
            controls = RegisterList(0x62, i2c, {})
        
        The provided I2C Device address will be used to contact the device which
        holds the registers over I2C. The `I2C Object </docs/i2c-object.md>`__
        depends on your platform, see the
        `documentation </docs/i2c-object.md>`__ for more information. In most
        cases you can provide an empty ``Register`` map as well.
        
        Defining Registers
        ------------------
        
        After you create a ``RegisterList`` you must define some ``Register``\ s
        to control. A ``Register`` is defined by a name (for easy programmatic
        access), an I2C address, and a string containing IO operation
        permissions. The ``RegisterList`` class provides a useful
        ``add(reg_name, reg_addr, reg_permissions, reg_segments)`` method for
        adding ``Register``\ s.
        
        .. code:: python
        
            from py_i2c_register.register import Register
            controls.add("REGISTER_NAME", 0x00, Registers.READ + Register.WRITE, {})
        
        This would define a ``Register`` with the name ``REGISTER_NAME``, the
        address ``0x00`` and the permission to read and write to/from it.
        
        Adding RegisterSegments
        -----------------------
        
        To actually read or write to/from a ``Register`` you need to define at
        least one ``RegisterSegment``. These describe how bits read from
        registers map to sub values. This could be useful if a device for
        example: provides a health register and each bit represents a different
        system's health. You define ``RegisterSegment``\ s by giving a name (for
        easy programmatic access) and the index of the segment's least and most
        significant bits. The previously mentioned ``RegisterList.add()`` method
        returns the ``Register`` that it just created. You can then in turn use
        a similar helper method that ``Register`` provides called
        ``add(seg_name, lsb_i, msb_i, default_bits)``:
        
        .. code:: python
        
            controls.add("HEALTH", 0x00, Registers.READ, {})\
                .add("LEFT_MOTOR_FLAG", 2, 2, [0])\
                .add("RIGHT_MOTOR_FLAG", 1, 1, [0])\
                .add("NETWORK_FLAG", 0, 0, [0])
        
        This would define a ``Register`` named ``HEALTH`` at address ``0x00``
        with read permissions. This ``Register`` would have 3
        ``RegisterSegment``\ s. These 3 register segments would look at bits 0,
        1, and 2 for the status of the left and right motors as well as some
        made up network module.
        
        Reading from RegisterSegments
        -----------------------------
        
        The ``RegisterList`` provides some useful helper methods for reading
        ``RegisterSegment``\ s as integer values. They are called ``to_int`` and
        ``to_twos_comp_int``. They both take the name of a ``Register`` and
        ``RegisterSegment`` to read. Optionally you can pass a ``read_first``
        value. When ``True`` these methods will read the ``Register`` off the
        I2C device before returning the ``RegisterSegment`` value:
        
        .. code:: python
        
            network_status = controls.to_int("HEALTH", "NETWORK_FLAG", read_first=True)
            velocity = controls.to_twos_comp_int("VELOCITY", "VELOCITY", read_first=True)
        
        This would read the ``NETWORK_FLAG`` segment of the ``HEALTH`` register
        and the ``VELOCITY`` segment of the ``VELOCITY`` register.
        
        Ontop of using ``RegisterList``\ s helper methods one can access raw
        ``RegisterSegment`` values via the ``RegisterSegment.bits`` array. This
        array contains the raw ``0`` or ``1`` values of the register. Just be
        sure to call ``Register.read`` before accessing the
        ``RegisterSegment.bits`` array:
        
        .. code:: python
        
            controls.get("VELOCITY").read()
            velocity_bits = controls.get("VELOCITY").get("VELOCITY").bits
        
        Writing to RegisterSegments
        ---------------------------
        
        The ``RegisterList`` class provides the ``set_bits`` and
        ``set_bits_from_int`` helper methods. Similar to the reading helper
        methods mentioned above ``set_bits`` and ``set_bits_from_int`` both also
        take a ``Register`` and ``RegisterSegment`` name as their first two
        parameters. The third value of both functions is the value to set. In
        the case of the ``set_bits`` method it is expected to be an array of
        bits to set. In the case of the ``set_bits_from_int`` method it is
        expected to be an integer value to set. The ``set_bits`` and
        ``set_bits_from_int`` methods also offer an optional ``write_after``
        flag. If ``True`` they will write the value of the ``Register`` to the
        I2C device after the value has been set.
        
        .. code:: python
        
            controls.set_bits("ACQ_COMMAND", "ACQ_COMMAND", [0, 0, 0, 0, 0, 1, 0, 0], write_after=True)  
            controls.set_bits_from_int("ACQ_COMMAND", "ACQ_COMMAND", 0x04, write_after=True)  
        
        This would set the ``ACQ_COMMAND`` segment of the ``ACQ_COMMAND``
        register to the value ``0x04`` using the ``set_bits`` and
        ``set_bits_from_int`` methods.
        
        Writing Wrapper Classes
        =======================
        
        I2C Register's simple architecture lends itself well to being used in
        hardware wrapper classes. All one must do is create a class with its own
        ``RegisterList`` instance. Then add ``Register`` and ``RegisterSegment``
        definitions in the ``__init__()`` method:
        
        .. code:: python
        
            from py_i2c_register.register_list import RegisterList
            from py_i2c_register.register import Register
        
            class LidarLiteV3():
                # Register and Segment name constants
                REG_ACQ_COMMAND = "ACQ_COMMAND"
                SEG_ACQ_COMMAND = REG_ACQ_COMMAND
        
                REG_STATUS = "STATUS"
                SEG_PROC_ERROR_FLAG = "PROC_ERROR_FLAG"
                SEG_HEALTH_FLAG = "HEALTH_FLAG"
                SEG_SECONDARY_RET_FLAG = "SECONDARY_RET_FLAG"
                SEG_INVALID_SIGNAL_FLAG = "INVALID_SIGNAL_FLAG"
                SEG_SIGNAL_OVERFLOW_FLAG = "SIGNAL_OVERFLOW_FLAG"
                SEG_REFERENCE_OVERFLOW_FLAG = "REFERENCE_OVERFLOW_FLAG"
                SEG_BUSY_FLAG = "BUSY_FLAG"
        
                REG_VELOCITY = "VELOCITY"
                SEG_VELOCITY= REG_VELOCITY
                
                REG_DISTANCE = "DISTANCE"
                SEG_DISTANCE = REG_DISTANCE
                
                def __init__(self):
                    # Create some device specific I2C Object
                    self.i2c = ...
                    
                    # Configure control registers
                    self.controls = RegisterList(0x62, self.i2c, {})
                    self.controls.add(LightLiteV3.REG_ACQ_COMMAND, 0x00, Register.WRITE, {}) \
                        .add(LightLiteV3.SEG_ACQ_COMMAND, 0, 7, [0] * 8)
        
                    self.controls.add(LightLiteV3.REG_STATUS, 0x01, Register.READ, {}) \
                        .add(LightLiteV3.SEG_PROC_ERROR_FLAG, 6, 6, [0]) \
                        .add(LightLiteV3.SEG_HEALTH_FLAG, 5, 5, [0]) \
                        .add(LightLiteV3.SEG_SECONDARY_RET_FLAG, 4, 4, [0]) \
                        .add(LightLiteV3.SEG_INVALID_SIGNAL_FLAG, 3, 3, [0]) \
                        .add(LightLiteV3.SEG_SIGNAL_OVERFLOW_FLAG, 2, 2, [0]) \
                        .add(LightLiteV3.SEG_REFERENCE_OVERFLOW_FLAG, 1, 1, [0]) \
                        .add(LightLiteV3.SEG_BUSY_FLAG, 0, 0, [0])
        
                    self.controls.add(LightLiteV3.REG_VELOCITY, 0x09, Register.READ, {})\
                        .add(LightLiteV3.SEG_VELOCITY, 0, 7, [0] * 8)
        
                    self.controls.add(LightLiteV3.REG_DISTANCE, 0x8f, Register.READ, {})\
                        .add(LightLiteV3.SEG_DISTANCE, 0, 15, [0] * 16)
                        
                # Provide useful helper methods
                def measure(self):
                    self.controls.set_bits_from_int(LidarLiteV3.REG_ACQ_COMMAND, LidarLiteV3.SEG_ACQ_COMMAND, 0x04, write_after=True)
                     
                def distance(self):
                    return self.controls.to_int(LidarLiteV3.REG_DISTANCE, LidarLiteV3.SEG_DISTANCE, read_first=True)
                
                def velocity(self):
                    return self.controls.to_int(LidarLiteV3.REG_VELOCITY, LidarLiteV3.SEG_VELOCITY, read_first=True)
        
            # Now using your hardware has never been easier
            lidar = LidarLiteV3()
        
            while True:
                lidar.measure()
                print("Car is going {} m/s when it was {} m away".format(lidar.velocity(), lidar.distance()))
        
        Development
        ===========
        
        The code for I2C Register is located in the ``py_i2c_register``
        directory. Feel free to contribute by opening a pull request. I try to
        test and document as much as I can.
        
        Supported Python Versions: 2.7, 3.6
        
        Running Tests
        -------------
        
        To run tests a couple python packages are required. To install them you
        can run the ``test-install`` Make target:
        
        .. code:: bash
        
            make test-install
        
        You can then run test by executing the ``test`` Make target:
        
        .. code:: bash
        
            make test
        
        To see a more detailed HTML report you can run the ``test-html`` Make
        target. The results will then be saved to ``htmlcov/index.html``.
        
        .. |Build Status| image:: https://travis-ci.org/Noah-Huppert/py-i2c-register.svg?branch=master
           :target: https://travis-ci.org/Noah-Huppert/py-i2c-register
        .. |Test Coverage| image:: https://codeclimate.com/github/Noah-Huppert/py-i2c-register/badges/coverage.svg
           :target: https://codeclimate.com/github/Noah-Huppert/py-i2c-register/coverage
        .. |Example Hardware Data Sheet Register Definitions page 1| image:: /docs/img/example-register-defs-p1.png
        .. |Example Hardware Data Sheet Register Definitions page 2| image:: /docs/img/example-register-defs-p2.png
        
        
Keywords: library i2c registers
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
