pynq.gpio — Python productivity for Zynq (Pynq) v1.0

# Source code for pynq.gpio

    #   Copyright (c) 2016, Xilinx, Inc.
    #   All rights reserved.
    #
    #   Redistribution and use in source and binary forms, with or without
    #   modification, are permitted provided that the following conditions are met:
    #
    #   1.  Redistributions of source code must retain the above copyright notice,
    #       this list of conditions and the following disclaimer.
    #
    #   2.  Redistributions in binary form must reproduce the above copyright
    #       notice, this list of conditions and the following disclaimer in the
    #       documentation and/or other materials provided with the distribution.
    #
    #   3.  Neither the name of the copyright holder nor the names of its
    #       contributors may be used to endorse or promote products derived from
    #       this software without specific prior written permission.
    #
    #   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    #   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    #   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    #   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
    #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    #   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    #   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    #   OR BUSINESS INTERRUPTION). HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    #   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    #   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    #   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    __author__      = "Yun Rock Qu"
    __copyright__   = "Copyright 2016, Xilinx"
    __email__       = "pynq_support@xilinx.com"

    import os
    import sys
    import struct
    from . import general_const

    class GPIO:
        """Class to wrap Linux's GPIO Sysfs API.

        This GPIO class does not handle PL I/O.

        Attributes
        ----------
        index : int
            The index of the GPIO, starting from the GPIO base.
        direction : str
            Input/output direction of the GPIO.
        path: str
            The path of the GPIO device in the linux system.

        """

        def __init__(self, gpio_index, direction):
            """Return a new GPIO object.

            Parameters
            ----------
            gpio_index : int
                The index of the GPIO using Linux's GPIO Sysfs API.
            direction : 'str'
                Input/output direction of the GPIO.

            """
            if not direction in ('in','out'):
                raise ValueError("Direction should be in or out.")
            self.index = gpio_index
            self.direction = direction
            self.path = '/sys/class/gpio/gpio{}/'.format(gpio_index)

            euid = os.geteuid()
            if euid != 0:
                raise EnvironmentError('Root permissions required.')

            if not os.path.exists(self.path):
                with open('/sys/class/gpio/export', 'w') as f:
                        f.write(str(self.index))

            with open(self.path + 'direction', 'w') as f:
                f.write(self.direction)

        def __del__(self):
            """Delete a GPIO object.

            Parameters
            ----------
            None

            Returns
            -------
            None

            """
            if os.path.exists(self.path):
                with open('/sys/class/gpio/unexport', 'w') as f:
                    f.write(str(self.index))

        def read(self):
            """The method to read a value from the GPIO.

            Parameters
            ----------
            None

            Returns
            -------
            int
                An integer read from the GPIO

            """
            if not self.direction is 'in':
                raise AttributeError("Cannot read GPIO output.")

            with open(self.path + 'value', 'r') as f:
                return int(f.read())

        def write(self, value):
            """The method to write a value into the GPIO.

            Parameters
            ----------
            value : int
                An integer value, either 0 or 1

            Returns
            -------
            None

            """
            if not self.direction is 'out':
                raise AttributeError("Cannot write GPIO input.")

            if not value in (0,1):
                raise ValueError("Can only write integer 0 or 1.")

            with open(self.path + 'value', 'w') as f:
                f.write(str(value))
            return

        @staticmethod
        def get_gpio_base():
            """This method returns the GPIO base using Linux's GPIO Sysfs API.

            This is a static method. To use:

            >>> from pynq import GPIO

            >>> gpio = GPIO.get_gpio_base()

            Note
            ----
            For path '/sys/class/gpio/gpiochip138/', this method returns 138.

            Parameters
            ----------
            None

            Returns
            -------
            int
                The GPIO index of the base.

            """
            for root, dirs, files in os.walk('/sys/class/gpio'):
                for name in dirs:
                    if 'gpiochip' in name:
                        return int(''.join(x for x in name if x.isdigit()))

        @staticmethod
        def get_gpio_pin(gpio_user_index):
            """This method returns a GPIO instance for PS GPIO pins.

            Users only need to specify an index starting from 0; this static
            method will map this index to the correct Linux GPIO pin number.

            Note
            ----
            The GPIO pin number can be calculated using:
            GPIO pin number = GPIO base + GPIO offset + user index
            e.g. The GPIO base is 138, and pin 54 is the base GPIO offset.
            Then the Linux GPIO pin would be (138 + 54 + 0) = 192.

            Parameters
            ----------
            gpio_user_index : int
                The index specified by users, starting from 0.

            Returns
            -------
            int
                The Linux Sysfs GPIO pin number.

            """
            return (GPIO.get_gpio_base() + general_const.GPIO_MIN_USER_PIN\
                    + gpio_user_index)