htpio.telnetio API documentation
Description: This is a telnet client i/o control module. Telnet is a client/server text-oriented communication protocol using a virtual terminal connection and …

# Module `htpio.telnetio`

This is a telnet client i/o control module. Telnet is a client/server text-oriented communication protocol using a virtual terminal connection and operates over TCP. It provides a command-line interface to the operating system on a remote host.

Example:

    import htpio.telnetio as telnetio

    r = telnetio.RaspberryPi(host = '192.168.199.31',
                             port = 23,
                             user = 'pi',
                             password = 'raspberry')

    try:
        r.lock(14)
    except:
        r.logout()
        raise

    r.configure(14, telnetio.RaspberryPi.OUTPUT)
    r.set(14, 1)

    print(r.get(14))

    r.unlock(14)
    r.deconfigure(14)

Source code

    # Copyright (c) Hilscher GmbH. All Rights Reserved.
    #
    # $Author: bgeorgiev $
    # $Date: 2019-05-16 11:34:02 +0300 (Thu, 16 May 2019) $
    # $Revision: 654 $

    """
    This is a telnet client i/o control module.
    Telnet is a client/server text-oriented communication protocol using a virtual
    terminal connection and operates over TCP. It provides a command-line interface
    to the operating system on a remote host.

    *** Example: ***

    ```python

    import htpio.telnetio as telnetio

    r = telnetio.RaspberryPi(host = '192.168.199.31',
                             port = 23,
                             user = 'pi',
                             password = 'raspberry')

    try:
        r.lock(14)
    except:
        r.logout()
        raise

    r.configure(14, telnetio.RaspberryPi.OUTPUT)
    r.set(14, 1)

    print(r.get(14))

    r.unlock(14)
    r.deconfigure(14)

    ```

    """

    # Compatibility imports
    from __future__ import unicode_literals
    from __future__ import absolute_import

    # Third party imports
    from telnetlib import Telnet

    # Local imports
    from htpio.bridge import Device
    from htpio.exceptions import PinLockedByOtherProcess
    from htpio.exceptions import InvalidLoginDetails
    from htpio.exceptions import CannotMountRamDisk
    from htpio.exceptions import CannotCreateLockDirectory

    """
    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    # DEVICE CLASSES : RaspberryPi, OrangePi, Arduino, etc.
    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    """

    class RaspberryPi(Telnet, Device):
        """
        RaspberryPi telnet remote i/o access class.

        This class provides basic functionality for controlling the GPIO by
        using a remote telnet session and sending commands to the operating system.

        ## Configuration

        The user should be part of the sudo and gpio group and the visudo file
        should be configured for no password prompt when using the sudo. This is
        accomplished by executing the following commands :

        ```
        sudo adduser htp
        sudo usermod -a -G gpio htp
        sudo usermod -a -G sudo htp

        sudo visudo
            (add line) htp     ALL=(ALL) NOPASSWD: ALL
            (add line) %gpio   ALL=(ALL) NOPASSWD: ALL

        ```

        ## Class attributes

            LOCK_DIR         Location of lock files (ramdisk)
            MAX_GPIO         Maximum number of gpio locks ( from 0 .. MAX)
            INPUT            GPIO is digital input
            OUTPUT           GPIO is digital output
            EOF              End of file

        ## Instance attributes

            host            : ip v4 address
            port            : port (from 0 to 65535)
            user            : user
            password        : user password
            login_prompt    : token to detect when login is expected
            password_prompt : token to detect when password is expected
            shell_prompt    : token to detect return after command execution
            timeout         : timeout time in case of connectivity problems

        ## Public methods

            islocked(gpio)              : Check if the gpio is locked
            lock(gpio)                  : Locks the gpio
            unlock(gpio)                : Unlocks the gpio
            isconfigured(gpio)          : Checks if the gpio is configured
            configure(gpio, direction)  : Configures the gpio with direction
            deconfigure(gpio)           : Restores the default configuration
            get(gpio)                   : Reads the gpio status
            set(gpio, value)            : Writes new value to gpio
            login()                     : Registers to the remote system
            logout()                    : Unregisters from the remote system
            reset()                     : Deletes all configuration data
        """

        LOCKDIR = "/tmp/htp/locks"
        """ Directory containing the lock files """

        RAMDISK = "htp_lockdir"
        """ Label for the ramdisk mounted on the lock directory """

        MAX_GPIO = 128
        """ Maximum number of gpio lock files """

        INPUT = 0
        """ Direction of gpio is input """

        OUTPUT = 1
        """ Direction of gpio is output """

        EOF = "\r\n"
        """ Character used to mark end of line transmission"""

        def __init__(
                self,
                host=None,
                port=23,
                user='htp',
                password='sokotnar',
                login_prompt="login:",
                password_prompt="Password:",
                shell_prompt="$",
                timeout=20
        ):

            """
            ## Constructor

            When called with host address, the constructor creates
            a telnet connection and performs automatic login:

            ```python
            import htpio.telnetio as telnetio

            t = telnetio.RaspberryPi('192.168.199.31')
            ```

            When called without host address, the constructor creates
            an unconnected instance. In this case the object might be
            configured by using the instance attributes:

            ```python
            import htpio.telnetio as telnetio

            t = telnetio.RaspberryPi()

            t.host = '192.168.199.31'
            t.port = 23
            t.user = 'user'
            t.password = 'password'
            t.login_prompt = 'login:'
            t.password_prompt = 'Password:'
            t.shell_prompt = '$'
            t.timeout = 20
            ```

            After the configuration above the user is required to use the
            following statements:

            ```python
            t.open(host, port)
            t.login()
            ```

            """

            Telnet.__init__(self, host, port)

            self.host = host
            self.port = port
            self.user = user
            self.password = password
            self.timeout = timeout

            self.login_prompt = login_prompt.encode('ascii')
            self.password_prompt = password_prompt.encode('ascii')
            self.shell_prompt = shell_prompt.encode('ascii')

            self._session = None
            self._locklist = None
            self._iotag = "gpio"

            self._lockdir = self.LOCKDIR
            self._ramdisk = self.RAMDISK

            if host is not None:
                self.login()

        def __del__(self):
            """ # Destructor -- close telnet connection"""

            self.close()

        """
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  islocked : Check if pin is locked and returns the owner
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def islocked(self, pin):
            """
            Check if pin is already locked by an object of this class and returns
            the identification number of the locking process.

            *** Shell: ***
            ```
            sudo cat /tmp/htp/locks/gpio14
            ```

            *** Example: ***
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')
            led.lock(14)
            if led.islocked(14) :
                print("LED is locked!!!")
            ...
            ```
            """

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            # GPIO lock file
            iotag = self._iotag + str(pin)
            lockfile = (self._lockdir + iotag)

            # Command to open file
            command = "sudo cat " + \
                      lockfile + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command result
            result = self.read_until(self.shell_prompt, self.timeout)
            result = bytes(result).decode()
            result = result.split()
            result = result[0].replace(self.EOF, "")

            # Verify result (should be a number)
            try:
                int(result)
            except ValueError:
                result = None

            return result

        """
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  lock : Checks if pin is used by other processes and creates a lock file
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def lock(self, pin):
            """
            Throws an exception <b>PinLockedByOtherProcess</b> or opens the gpio
            lock file and writes the session id in it.

            ***Shell***:
            ```shell
            echo 1921681993055555 | sudo tee /tmp/htp/gpio14
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')
            led.lock(14)
            ...
            ```
            """

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            # GPIO lock file
            iotag = self._iotag + str(pin)
            lockfile = self._lockdir + iotag

            # Create lock file
            lock_owner = self.islocked(pin)
            if lock_owner is not None:
                raise PinLockedByOtherProcess(lock_owner, self._session)
            else:
                command = "echo " + \
                          self._session + \
                          " | sudo tee " + \
                          lockfile + \
                          self.EOF

                self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  unlock : Deltetes the lock file
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def unlock(self, pin, ):
            """
            Unlocks the gpio by deleting the content of the lock file.

            ***Shell***:
            ```shell
            sudo truncate --size=0 /tmp/htp/locks/gpio14
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')
            led.unlock(14)
            ...
            ```

            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            # GPIO lock file
            iotag = self._iotag + str(pin)
            lockfile = self._lockdir + iotag

            # Empty lock file
            command = "sudo truncate --size=0 " + \
                      lockfile + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        # isconfigured : Checks for folders with the name gpioXX
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def isconfigured(self, pin):
            """
            This function checks if the sysfs folder /sys/class/gpio/gpioNN exists.

            ***Shell:***
            ```shell
            find /sys/class/gpio -name gpio14
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.configure(14, telnetio.RaspberryPi.OUTPUT)
            if led.isconfigured(14):
                print("LED is configured!!!")
            ...
            ```
            """

            # Dictionary to transform mode strings to integers
            modes = {
                "in": self.INPUT,
                "out": self.OUTPUT,
            }

            # GPIO to check
            iotag = self._iotag + str(pin)

            # Check if pin folder is exported
            # find /sys/class/gpio -name gpio14
            command = "find " + \
                      "/sys/class/gpio " + \
                      "-name gpio[0-9][0-9]" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command response
            result = self.read_until(self.shell_prompt, self.timeout)
            result = bytes(result).decode()
            result = result.split(self.EOF)

            # Evaluate result in case sysfs folder exists
            if any(iotag in folders for folders in result):

                # Command to open file
                # sudo cat /sys/class/gpio/gpio14/direction
                command = "sudo cat " + \
                           "/sys/class/gpio/" + \
                           iotag + "/" + \
                           "direction" + \
                           self.EOF

                self.write(command.encode('ascii'))

                # Flush command echo
                self.read_until(self.EOF.encode('ascii'), self.timeout)

                # Read command result
                val = self.read_until(self.shell_prompt, self.timeout)
                val = bytes(val).decode()
                val = val.split()
                val = val[0].replace(self.EOF, "")
                val = val.lower()
                val = modes.get(val)

            else:
                val = 0

            return val

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  configure : Configures pin for use through the file system
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def configure(self, pin, direction):
            """
            Create the sysfs virtual folder for gpio manipulation.

            *** Shell : ***
            ```shell
            echo 14 | tee /sys/class/gpio/export
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.configure(14, telnetio.RaspberryPi.OUTPUT)
            ...
            ```

            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Configure pin
            if not self.isconfigured(pin):

                # Export the desired pin (creates virtual folder)
                command = "echo " + \
                          str(pin) + \
                          " | tee /sys/class/gpio/export" + \
                          self.EOF

                self.write(command.encode('ascii'))

                # Flush buffer
                self.read_until(self.shell_prompt, self.timeout)

            # Configure the type of the pin = IN
            if direction == self.INPUT:
                command = "echo in | sudo tee /sys/class/gpio/gpio" + \
                          str(pin) + \
                          "/direction" + \
                          self.EOF

                self.write(command.encode('ascii'))

            # Configure the type of the pin = OUT
            if direction == self.OUTPUT:
                command = "echo out | sudo tee /sys/class/gpio/gpio" + \
                          str(pin) + \
                          "/direction" + \
                          self.EOF

                self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  cleanup : Deletes the current configuration of the pin
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def deconfigure(self, pin):
            """
            Delete the sysfs virtual folder for pin manipulation.

            *** Shell : ***
            ```
            echo 14 | tee /sys/class/gpio/unexport
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.deconfigure(14)
            ...
            ```
            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Unexport desired pin (deletes virtual folder)
            command = "echo " + \
                      str(pin) + \
                      " | tee /sys/class/gpio/unexport" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  get : Reads the value of the pin using the file system
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def get(self, pin):
            """
            Gets the current status of the given pin by reading the system file.

            *** Shell : ***
            ```shell
            cat /sys/class/gpio/gpio14/value
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.get(14)
            ...
            ```
            """

            command = "cat " + \
                      "/sys/class/gpio/gpio" + \
                      str(pin) + \
                      "/value" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command results
            value = self.read_until(self.EOF.encode('ascii'), self.timeout)
            value = bytes(value).decode()

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return int(value.replace(self.EOF, ""))

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  set : Writes to the pin using the file system
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def set(self, pin, value):
            """
            Sets the current value of the given pin by using the system file.

            *** Shell: ***
            ```
            echo 1 | sudo tee /sys/class/gpio/gpio14
            ```

            *** Example: ***
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.configure(14, telnetio.RaspberryPi.OUTPUT)
            led.set(14, 1)
            ...
            ```
            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Write to the desired pin (virtual file "value")
            command = "echo " + \
                      str(value) + \
                      " | sudo tee /sys/class/gpio/gpio" + \
                      str(pin) + \
                      "/value" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  login : sends username and password to the telnet server
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def login(self):
            """
            Performs an automatic login to the remote system using the supplied
            user and password as instance properties.

            !!! Use only when creating an unconnected instance !!!

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi()
            led.host = '192.168.199.31'
            led.port = 23
            led.user = 'htpio'
            led.password = 'sokotnar'

            led.open(host, port)
            led.login()

            ...
            ```
            """

            # Check if device already registered for use
            if not self._session:

                # Flush buffer and wait for login
                self.read_until(self.login_prompt, self.timeout)
                command = self.user + self.EOF
                self.write(command.encode('ascii'))

                # Flush buffer and wait for password
                self.read_until(self.password_prompt, self.timeout)
                command = self.password + self.EOF
                self.write(command.encode('ascii'))

                # Flush buffer
                result = self.read_until(self.shell_prompt, self.timeout)
                result = bytes(result).decode()

                if any('incorrect' in s for s in result.split()):
                    raise InvalidLoginDetails
                else:
                    self._session = self.__session()
                    self.__makedir()

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  logout : Closes telnet connection
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def logout(self):
            """
            Closes the connection to the target.

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.logout()

            ...
            ```
            """

            # Add additional steps before closing the connection
            self.close()

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  reset : Initializes telnetio
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def reset(self, pin):
            """
            Deletes lock file for pin.

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.reset(14)

            ...
            ```
            """

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            iotag = self._iotag + str(pin)
            lockfile = self._lockdir + iotag

            # Delete lock file
            command = "sudo rm " + \
                      lockfile + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  __islockdir : Creates lock directory if not present
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __islockdir(self):
            """
            Checks if the lock directory exists.

            ```
            [ -d /tmp/htp/locks ] && echo 1 || echo 0
            ```
            """

            command = "[ -d " + \
                      self._lockdir + \
                      " ] " + \
                      "&& echo 1 || echo 0" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command line echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command result
            result = self.read_until(self.EOF.encode('ascii'), self.timeout)
            result = bytes(result).decode()
            result = result.replace(self.EOF, "")

            return int(result)

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  __makedir : Creates lock directory if not present
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __makedir(self, folder=None):
            """
            Create the lock directory (stores the lock files).

            ```
            sudo mkdir -p /tmp/htp/locks
            ```
            """

            # Define lock folder name
            if folder is None:
                folder = self._lockdir
            else:
                self._lockdir = folder

            # Check and create lock directory
            if not self.__islockdir():

                command = "sudo mkdir -p " + \
                          folder + \
                          self.EOF

                self.write(command.encode('ascii'))

                if not self.__islockdir():
                    raise CannotCreateLockDirectory

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            # Mount ram disk
            self.__mount(folder)

            return 0

        """
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  __ismounted : Check if ram disk mounted to lock directory
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __ismounted(self, ramdisk=None):
            """
            Check if ram disk is mounted on lock directory.

            ```
            mount | grep -i tmpfs
            ```
            """

            # Check if ram disk mounted
            command = "mount | grep -i " + \
                      ramdisk + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command result
            result = self.read_until(self.shell_prompt, self.timeout)
            result = bytes(result).decode()

            if any(ramdisk in mounts for mounts in result.split()):
                val = True
            else:
                val = False

            return val

        """
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  __mount : Mount ram disk
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __mount(self, folder=None):
            """
            Mount ram disk to lock folder. This is required to remove the problem
            of frequent read/write operations on the SD card.

            ```
            sudo mount -t tmpfs -o size=16m htp_ramdisk /tmp/htp/locks
            ```
            """

            if not self.__ismounted(folder):

                command = "sudo mount -t tmpfs -o size=16m " + \
                          self._ramdisk + \
                          " " + \
                          self._lockdir + \
                          self.EOF

                self.write(command.encode('ascii'))

                # Flush buffer
                self.read_until(self.shell_prompt, self.timeout)

                if not self.__ismounted(folder):
                    raise CannotMountRamDisk

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  dismount : Ejects RAMDISK used to store the locksfiles
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __dismount(self, folder=None):
            """
            Dismounts htp ramdisk from lock folder directory.

            ```
            sudo umount /tmp/htp/locks
            ```
            """

            if folder is None:
                folder = self._lockdir

            # Unmount ram disk
            command = "sudo umount " + \
                      folder + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  session : Retrieves the current telnet session
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __session(self):
            """
            Gets the socket data for this connection and converts the to one
            unique identification number. This ID is used to lock gpios.
            """

            mysocket = self.sock
            mysocket = mysocket.getsockname()
            result = '.'.join(map(str, mysocket))
            result = result.replace(".", "")

            return result

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  locklist : retries all gpios currently locked by other processes
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __locklist(self):
            """
            Gets a listing of all lock files in the lock directory.

            ```
            ls /tmp/htp/locks
            ```
            """

            # List the content of the lock directory
            command = "ls " + \
                      self._lockdir + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command results
            self._locklist = self.read_until(self.shell_prompt, self.timeout)
            self._locklist = self._locklist.split()

            return self._locklist

        """
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #  populate : generate GPIO lock files from 0 to MAX_GPIO
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        """

        def __populate(self):
            """
            Creates all lock files in the lock directory.

            ```
            touch -a gpio14
            ```
            """

            # Consistent directory name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            # Create lock files
            for gpio in range(self.MAX_GPIO):
                iotag = self._iotag + str(gpio)
                lockfile = self._lockdir + iotag

                command = "touch -a " + \
                          lockfile + \
                          self.EOF

                self.write(command.encode('ascii'))

                # Flush buffer
                self.read_until(self.shell_prompt, self.timeout)

            return 0

## Classes

`class RaspberryPi (host=None, port=23, user='htp', password='sokotnar', login_prompt='login:', password_prompt='Password:', shell_prompt='$', timeout=20)`

  RaspberryPi telnet remote i/o access class.

  This class provides basic functionality for controlling the GPIO by using a remote telnet session and sending commands to the operating system.

  ## Configuration

  The user should be part of the sudo and gpio group and the visudo file should be configured for no password prompt when using the sudo. This is accomplished by executing the following commands :

      sudo adduser htp
      sudo usermod -a -G gpio htp
      sudo usermod -a -G sudo htp

      sudo visudo
          (add line) htp     ALL=(ALL) NOPASSWD: ALL
          (add line) %gpio   ALL=(ALL) NOPASSWD: ALL

  ## Class attributes

      LOCK_DIR         Location of lock files (ramdisk)
      MAX_GPIO         Maximum number of gpio locks ( from 0 .. MAX)
      INPUT            GPIO is digital input
      OUTPUT           GPIO is digital output
      EOF              End of file

  ## Instance attributes

      host            : ip v4 address
      port            : port (from 0 to 65535)
      user            : user
      password        : user password
      login_prompt    : token to detect when login is expected
      password_prompt : token to detect when password is expected
      shell_prompt    : token to detect return after command execution
      timeout         : timeout time in case of connectivity problems

  ## Public methods

      islocked(gpio)              : Check if the gpio is locked
      lock(gpio)                  : Locks the gpio
      unlock(gpio)                : Unlocks the gpio
      isconfigured(gpio)          : Checks if the gpio is configured
      configure(gpio, direction)  : Configures the gpio with direction
      deconfigure(gpio)           : Restores the default configuration
      get(gpio)                   : Reads the gpio status
      set(gpio, value)            : Writes new value to gpio
      login()                     : Registers to the remote system
      logout()                    : Unregisters from the remote system
      reset()                     : Deletes all configuration data

  ## Constructor

  When called with host address, the constructor creates a telnet connection and performs automatic login:

      import htpio.telnetio as telnetio

      t = telnetio.RaspberryPi('192.168.199.31')

  When called without host address, the constructor creates an unconnected instance. In this case the object might be configured by using the instance attributes:

      import htpio.telnetio as telnetio

      t = telnetio.RaspberryPi()

      t.host = '192.168.199.31'
      t.port = 23
      t.user = 'user'
      t.password = 'password'
      t.login_prompt = 'login:'
      t.password_prompt = 'Password:'
      t.shell_prompt = '$'
      t.timeout = 20

  After the configuration above the user is required to use the following statements:

      t.open(host, port)
      t.login()

  Source code

      class RaspberryPi(Telnet, Device):
          """
          RaspberryPi telnet remote i/o access class.

          This class provides basic functionality for controlling the GPIO by
          using a remote telnet session and sending commands to the operating system.

          ## Configuration

          The user should be part of the sudo and gpio group and the visudo file
          should be configured for no password prompt when using the sudo. This is
          accomplished by executing the following commands :

          ```
          sudo adduser htp
          sudo usermod -a -G gpio htp
          sudo usermod -a -G sudo htp

          sudo visudo
              (add line) htp     ALL=(ALL) NOPASSWD: ALL
              (add line) %gpio   ALL=(ALL) NOPASSWD: ALL

          ```

          ## Class attributes

              LOCK_DIR         Location of lock files (ramdisk)
              MAX_GPIO         Maximum number of gpio locks ( from 0 .. MAX)
              INPUT            GPIO is digital input
              OUTPUT           GPIO is digital output
              EOF              End of file

          ## Instance attributes

              host            : ip v4 address
              port            : port (from 0 to 65535)
              user            : user
              password        : user password
              login_prompt    : token to detect when login is expected
              password_prompt : token to detect when password is expected
              shell_prompt    : token to detect return after command execution
              timeout         : timeout time in case of connectivity problems

          ## Public methods

              islocked(gpio)              : Check if the gpio is locked
              lock(gpio)                  : Locks the gpio
              unlock(gpio)                : Unlocks the gpio
              isconfigured(gpio)          : Checks if the gpio is configured
              configure(gpio, direction)  : Configures the gpio with direction
              deconfigure(gpio)           : Restores the default configuration
              get(gpio)                   : Reads the gpio status
              set(gpio, value)            : Writes new value to gpio
              login()                     : Registers to the remote system
              logout()                    : Unregisters from the remote system
              reset()                     : Deletes all configuration data
          """

          LOCKDIR = "/tmp/htp/locks"
          """ Directory containing the lock files """

          RAMDISK = "htp_lockdir"
          """ Label for the ramdisk mounted on the lock directory """

          MAX_GPIO = 128
          """ Maximum number of gpio lock files """

          INPUT = 0
          """ Direction of gpio is input """

          OUTPUT = 1
          """ Direction of gpio is output """

          EOF = "\r\n"
          """ Character used to mark end of line transmission"""

          def __init__(
                  self,
                  host=None,
                  port=23,
                  user='htp',
                  password='sokotnar',
                  login_prompt="login:",
                  password_prompt="Password:",
                  shell_prompt="$",
                  timeout=20
          ):

              """
              ## Constructor

              When called with host address, the constructor creates
              a telnet connection and performs automatic login:

              ```python
              import htpio.telnetio as telnetio

              t = telnetio.RaspberryPi('192.168.199.31')
              ```

              When called without host address, the constructor creates
              an unconnected instance. In this case the object might be
              configured by using the instance attributes:

              ```python
              import htpio.telnetio as telnetio

              t = telnetio.RaspberryPi()

              t.host = '192.168.199.31'
              t.port = 23
              t.user = 'user'
              t.password = 'password'
              t.login_prompt = 'login:'
              t.password_prompt = 'Password:'
              t.shell_prompt = '$'
              t.timeout = 20
              ```

              After the configuration above the user is required to use the
              following statements:

              ```python
              t.open(host, port)
              t.login()
              ```

              """

              Telnet.__init__(self, host, port)

              self.host = host
              self.port = port
              self.user = user
              self.password = password
              self.timeout = timeout

              self.login_prompt = login_prompt.encode('ascii')
              self.password_prompt = password_prompt.encode('ascii')
              self.shell_prompt = shell_prompt.encode('ascii')

              self._session = None
              self._locklist = None
              self._iotag = "gpio"

              self._lockdir = self.LOCKDIR
              self._ramdisk = self.RAMDISK

              if host is not None:
                  self.login()

          def __del__(self):
              """ # Destructor -- close telnet connection"""

              self.close()

          """
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  islocked : Check if pin is locked and returns the owner
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def islocked(self, pin):
              """
              Check if pin is already locked by an object of this class and returns
              the identification number of the locking process.

              *** Shell: ***
              ```
              sudo cat /tmp/htp/locks/gpio14
              ```

              *** Example: ***
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')
              led.lock(14)
              if led.islocked(14) :
                  print("LED is locked!!!")
              ...
              ```
              """

              # Consistent folder name
              if not self._lockdir.endswith("/"):
                  self._lockdir = self._lockdir + "/"

              # GPIO lock file
              iotag = self._iotag + str(pin)
              lockfile = (self._lockdir + iotag)

              # Command to open file
              command = "sudo cat " + \
                        lockfile + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush command echo
              self.read_until(self.EOF.encode('ascii'), self.timeout)

              # Read command result
              result = self.read_until(self.shell_prompt, self.timeout)
              result = bytes(result).decode()
              result = result.split()
              result = result[0].replace(self.EOF, "")

              # Verify result (should be a number)
              try:
                  int(result)
              except ValueError:
                  result = None

              return result

          """
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  lock : Checks if pin is used by other processes and creates a lock file
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def lock(self, pin):
              """
              Throws an exception <b>PinLockedByOtherProcess</b> or opens the gpio
              lock file and writes the session id in it.

              ***Shell***:
              ```shell
              echo 1921681993055555 | sudo tee /tmp/htp/gpio14
              ```

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')
              led.lock(14)
              ...
              ```
              """

              # Consistent folder name
              if not self._lockdir.endswith("/"):
                  self._lockdir = self._lockdir + "/"

              # GPIO lock file
              iotag = self._iotag + str(pin)
              lockfile = self._lockdir + iotag

              # Create lock file
              lock_owner = self.islocked(pin)
              if lock_owner is not None:
                  raise PinLockedByOtherProcess(lock_owner, self._session)
              else:
                  command = "echo " + \
                            self._session + \
                            " | sudo tee " + \
                            lockfile + \
                            self.EOF

                  self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  unlock : Deltetes the lock file
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def unlock(self, pin, ):
              """
              Unlocks the gpio by deleting the content of the lock file.

              ***Shell***:
              ```shell
              sudo truncate --size=0 /tmp/htp/locks/gpio14
              ```

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')
              led.unlock(14)
              ...
              ```

              """

              # Verify is pin is locked by other process
              lock_owner = self.islocked(pin)
              if lock_owner is not None and lock_owner != self._session:
                  raise PinLockedByOtherProcess(lock_owner, self._session)

              # Consistent folder name
              if not self._lockdir.endswith("/"):
                  self._lockdir = self._lockdir + "/"

              # GPIO lock file
              iotag = self._iotag + str(pin)
              lockfile = self._lockdir + iotag

              # Empty lock file
              command = "sudo truncate --size=0 " + \
                        lockfile + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          # isconfigured : Checks for folders with the name gpioXX
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def isconfigured(self, pin):
              """
              This function checks if the sysfs folder /sys/class/gpio/gpioNN exists.

              ***Shell:***
              ```shell
              find /sys/class/gpio -name gpio14
              ```

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')

              led.configure(14, telnetio.RaspberryPi.OUTPUT)
              if led.isconfigured(14):
                  print("LED is configured!!!")
              ...
              ```
              """

              # Dictionary to transform mode strings to integers
              modes = {
                  "in": self.INPUT,
                  "out": self.OUTPUT,
              }

              # GPIO to check
              iotag = self._iotag + str(pin)

              # Check if pin folder is exported
              # find /sys/class/gpio -name gpio14
              command = "find " + \
                        "/sys/class/gpio " + \
                        "-name gpio[0-9][0-9]" + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush command echo
              self.read_until(self.EOF.encode('ascii'), self.timeout)

              # Read command response
              result = self.read_until(self.shell_prompt, self.timeout)
              result = bytes(result).decode()
              result = result.split(self.EOF)

              # Evaluate result in case sysfs folder exists
              if any(iotag in folders for folders in result):

                  # Command to open file
                  # sudo cat /sys/class/gpio/gpio14/direction
                  command = "sudo cat " + \
                             "/sys/class/gpio/" + \
                             iotag + "/" + \
                             "direction" + \
                             self.EOF

                  self.write(command.encode('ascii'))

                  # Flush command echo
                  self.read_until(self.EOF.encode('ascii'), self.timeout)

                  # Read command result
                  val = self.read_until(self.shell_prompt, self.timeout)
                  val = bytes(val).decode()
                  val = val.split()
                  val = val[0].replace(self.EOF, "")
                  val = val.lower()
                  val = modes.get(val)

              else:
                  val = 0

              return val

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  configure : Configures pin for use through the file system
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def configure(self, pin, direction):
              """
              Create the sysfs virtual folder for gpio manipulation.

              *** Shell : ***
              ```shell
              echo 14 | tee /sys/class/gpio/export
              ```

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')

              led.configure(14, telnetio.RaspberryPi.OUTPUT)
              ...
              ```

              """

              # Verify is pin is locked by other process
              lock_owner = self.islocked(pin)
              if lock_owner is not None and lock_owner != self._session:
                  raise PinLockedByOtherProcess(lock_owner, self._session)

              # Configure pin
              if not self.isconfigured(pin):

                  # Export the desired pin (creates virtual folder)
                  command = "echo " + \
                            str(pin) + \
                            " | tee /sys/class/gpio/export" + \
                            self.EOF

                  self.write(command.encode('ascii'))

                  # Flush buffer
                  self.read_until(self.shell_prompt, self.timeout)

              # Configure the type of the pin = IN
              if direction == self.INPUT:
                  command = "echo in | sudo tee /sys/class/gpio/gpio" + \
                            str(pin) + \
                            "/direction" + \
                            self.EOF

                  self.write(command.encode('ascii'))

              # Configure the type of the pin = OUT
              if direction == self.OUTPUT:
                  command = "echo out | sudo tee /sys/class/gpio/gpio" + \
                            str(pin) + \
                            "/direction" + \
                            self.EOF

                  self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  cleanup : Deletes the current configuration of the pin
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def deconfigure(self, pin):
              """
              Delete the sysfs virtual folder for pin manipulation.

              *** Shell : ***
              ```
              echo 14 | tee /sys/class/gpio/unexport
              ```

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')

              led.deconfigure(14)
              ...
              ```
              """

              # Verify is pin is locked by other process
              lock_owner = self.islocked(pin)
              if lock_owner is not None and lock_owner != self._session:
                  raise PinLockedByOtherProcess(lock_owner, self._session)

              # Unexport desired pin (deletes virtual folder)
              command = "echo " + \
                        str(pin) + \
                        " | tee /sys/class/gpio/unexport" + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  get : Reads the value of the pin using the file system
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def get(self, pin):
              """
              Gets the current status of the given pin by reading the system file.

              *** Shell : ***
              ```shell
              cat /sys/class/gpio/gpio14/value
              ```

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')

              led.get(14)
              ...
              ```
              """

              command = "cat " + \
                        "/sys/class/gpio/gpio" + \
                        str(pin) + \
                        "/value" + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush command echo
              self.read_until(self.EOF.encode('ascii'), self.timeout)

              # Read command results
              value = self.read_until(self.EOF.encode('ascii'), self.timeout)
              value = bytes(value).decode()

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return int(value.replace(self.EOF, ""))

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  set : Writes to the pin using the file system
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def set(self, pin, value):
              """
              Sets the current value of the given pin by using the system file.

              *** Shell: ***
              ```
              echo 1 | sudo tee /sys/class/gpio/gpio14
              ```

              *** Example: ***
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')

              led.configure(14, telnetio.RaspberryPi.OUTPUT)
              led.set(14, 1)
              ...
              ```
              """

              # Verify is pin is locked by other process
              lock_owner = self.islocked(pin)
              if lock_owner is not None and lock_owner != self._session:
                  raise PinLockedByOtherProcess(lock_owner, self._session)

              # Write to the desired pin (virtual file "value")
              command = "echo " + \
                        str(value) + \
                        " | sudo tee /sys/class/gpio/gpio" + \
                        str(pin) + \
                        "/value" + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  login : sends username and password to the telnet server
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def login(self):
              """
              Performs an automatic login to the remote system using the supplied
              user and password as instance properties.

              !!! Use only when creating an unconnected instance !!!

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi()
              led.host = '192.168.199.31'
              led.port = 23
              led.user = 'htpio'
              led.password = 'sokotnar'

              led.open(host, port)
              led.login()

              ...
              ```
              """

              # Check if device already registered for use
              if not self._session:

                  # Flush buffer and wait for login
                  self.read_until(self.login_prompt, self.timeout)
                  command = self.user + self.EOF
                  self.write(command.encode('ascii'))

                  # Flush buffer and wait for password
                  self.read_until(self.password_prompt, self.timeout)
                  command = self.password + self.EOF
                  self.write(command.encode('ascii'))

                  # Flush buffer
                  result = self.read_until(self.shell_prompt, self.timeout)
                  result = bytes(result).decode()

                  if any('incorrect' in s for s in result.split()):
                      raise InvalidLoginDetails
                  else:
                      self._session = self.__session()
                      self.__makedir()

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  logout : Closes telnet connection
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def logout(self):
              """
              Closes the connection to the target.

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')

              led.logout()

              ...
              ```
              """

              # Add additional steps before closing the connection
              self.close()

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  reset : Initializes telnetio
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def reset(self, pin):
              """
              Deletes lock file for pin.

              ***Example***:
              ```python
              import htpio.telnetio as telnetio

              led = telnetio.RaspberryPi('192.168.199.31')

              led.reset(14)

              ...
              ```
              """

              # Consistent folder name
              if not self._lockdir.endswith("/"):
                  self._lockdir = self._lockdir + "/"

              iotag = self._iotag + str(pin)
              lockfile = self._lockdir + iotag

              # Delete lock file
              command = "sudo rm " + \
                        lockfile + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  __islockdir : Creates lock directory if not present
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __islockdir(self):
              """
              Checks if the lock directory exists.

              ```
              [ -d /tmp/htp/locks ] && echo 1 || echo 0
              ```
              """

              command = "[ -d " + \
                        self._lockdir + \
                        " ] " + \
                        "&& echo 1 || echo 0" + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush command line echo
              self.read_until(self.EOF.encode('ascii'), self.timeout)

              # Read command result
              result = self.read_until(self.EOF.encode('ascii'), self.timeout)
              result = bytes(result).decode()
              result = result.replace(self.EOF, "")

              return int(result)

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  __makedir : Creates lock directory if not present
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __makedir(self, folder=None):
              """
              Create the lock directory (stores the lock files).

              ```
              sudo mkdir -p /tmp/htp/locks
              ```
              """

              # Define lock folder name
              if folder is None:
                  folder = self._lockdir
              else:
                  self._lockdir = folder

              # Check and create lock directory
              if not self.__islockdir():

                  command = "sudo mkdir -p " + \
                            folder + \
                            self.EOF

                  self.write(command.encode('ascii'))

                  if not self.__islockdir():
                      raise CannotCreateLockDirectory

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              # Mount ram disk
              self.__mount(folder)

              return 0

          """
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  __ismounted : Check if ram disk mounted to lock directory
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __ismounted(self, ramdisk=None):
              """
              Check if ram disk is mounted on lock directory.

              ```
              mount | grep -i tmpfs
              ```
              """

              # Check if ram disk mounted
              command = "mount | grep -i " + \
                        ramdisk + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.EOF.encode('ascii'), self.timeout)

              # Read command result
              result = self.read_until(self.shell_prompt, self.timeout)
              result = bytes(result).decode()

              if any(ramdisk in mounts for mounts in result.split()):
                  val = True
              else:
                  val = False

              return val

          """
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  __mount : Mount ram disk
          #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __mount(self, folder=None):
              """
              Mount ram disk to lock folder. This is required to remove the problem
              of frequent read/write operations on the SD card.

              ```
              sudo mount -t tmpfs -o size=16m htp_ramdisk /tmp/htp/locks
              ```
              """

              if not self.__ismounted(folder):

                  command = "sudo mount -t tmpfs -o size=16m " + \
                            self._ramdisk + \
                            " " + \
                            self._lockdir + \
                            self.EOF

                  self.write(command.encode('ascii'))

                  # Flush buffer
                  self.read_until(self.shell_prompt, self.timeout)

                  if not self.__ismounted(folder):
                      raise CannotMountRamDisk

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  dismount : Ejects RAMDISK used to store the locksfiles
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __dismount(self, folder=None):
              """
              Dismounts htp ramdisk from lock folder directory.

              ```
              sudo umount /tmp/htp/locks
              ```
              """

              if folder is None:
                  folder = self._lockdir

              # Unmount ram disk
              command = "sudo umount " + \
                        folder + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush buffer
              self.read_until(self.shell_prompt, self.timeout)

              return 0

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  session : Retrieves the current telnet session
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __session(self):
              """
              Gets the socket data for this connection and converts the to one
              unique identification number. This ID is used to lock gpios.
              """

              mysocket = self.sock
              mysocket = mysocket.getsockname()
              result = '.'.join(map(str, mysocket))
              result = result.replace(".", "")

              return result

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  locklist : retries all gpios currently locked by other processes
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __locklist(self):
              """
              Gets a listing of all lock files in the lock directory.

              ```
              ls /tmp/htp/locks
              ```
              """

              # List the content of the lock directory
              command = "ls " + \
                        self._lockdir + \
                        self.EOF

              self.write(command.encode('ascii'))

              # Flush command echo
              self.read_until(self.EOF.encode('ascii'), self.timeout)

              # Read command results
              self._locklist = self.read_until(self.shell_prompt, self.timeout)
              self._locklist = self._locklist.split()

              return self._locklist

          """
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          #  populate : generate GPIO lock files from 0 to MAX_GPIO
          #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          """

          def __populate(self):
              """
              Creates all lock files in the lock directory.

              ```
              touch -a gpio14
              ```
              """

              # Consistent directory name
              if not self._lockdir.endswith("/"):
                  self._lockdir = self._lockdir + "/"

              # Create lock files
              for gpio in range(self.MAX_GPIO):
                  iotag = self._iotag + str(gpio)
                  lockfile = self._lockdir + iotag

                  command = "touch -a " + \
                            lockfile + \
                            self.EOF

                  self.write(command.encode('ascii'))

                  # Flush buffer
                  self.read_until(self.shell_prompt, self.timeout)

              return 0

  ### Ancestors

  - telnetlib.Telnet
  - Device

  ### Class variables

  `var EOF`

    Character used to mark end of line transmission

  `var LOCKDIR`

    Directory containing the lock files

  `var MAX_GPIO`

    Maximum number of gpio lock files

  `var RAMDISK`

    Label for the ramdisk mounted on the lock directory

  ### Methods

  `def configure(self, pin, direction)`

    Create the sysfs virtual folder for gpio manipulation.

    Shell :

        echo 14 | tee /sys/class/gpio/export

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')

        led.configure(14, telnetio.RaspberryPi.OUTPUT)
        ...

    Source code

        def configure(self, pin, direction):
            """
            Create the sysfs virtual folder for gpio manipulation.

            *** Shell : ***
            ```shell
            echo 14 | tee /sys/class/gpio/export
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.configure(14, telnetio.RaspberryPi.OUTPUT)
            ...
            ```

            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Configure pin
            if not self.isconfigured(pin):

                # Export the desired pin (creates virtual folder)
                command = "echo " + \
                          str(pin) + \
                          " | tee /sys/class/gpio/export" + \
                          self.EOF

                self.write(command.encode('ascii'))

                # Flush buffer
                self.read_until(self.shell_prompt, self.timeout)

            # Configure the type of the pin = IN
            if direction == self.INPUT:
                command = "echo in | sudo tee /sys/class/gpio/gpio" + \
                          str(pin) + \
                          "/direction" + \
                          self.EOF

                self.write(command.encode('ascii'))

            # Configure the type of the pin = OUT
            if direction == self.OUTPUT:
                command = "echo out | sudo tee /sys/class/gpio/gpio" + \
                          str(pin) + \
                          "/direction" + \
                          self.EOF

                self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

  `def deconfigure(self, pin)`

    Delete the sysfs virtual folder for pin manipulation.

    Shell :

        echo 14 | tee /sys/class/gpio/unexport

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')

        led.deconfigure(14)
        ...

    Source code

        def deconfigure(self, pin):
            """
            Delete the sysfs virtual folder for pin manipulation.

            *** Shell : ***
            ```
            echo 14 | tee /sys/class/gpio/unexport
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.deconfigure(14)
            ...
            ```
            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Unexport desired pin (deletes virtual folder)
            command = "echo " + \
                      str(pin) + \
                      " | tee /sys/class/gpio/unexport" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

  `def get(self, pin)`

    Gets the current status of the given pin by reading the system file.

    Shell :

        cat /sys/class/gpio/gpio14/value

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')

        led.get(14)
        ...

    Source code

        def get(self, pin):
            """
            Gets the current status of the given pin by reading the system file.

            *** Shell : ***
            ```shell
            cat /sys/class/gpio/gpio14/value
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.get(14)
            ...
            ```
            """

            command = "cat " + \
                      "/sys/class/gpio/gpio" + \
                      str(pin) + \
                      "/value" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command results
            value = self.read_until(self.EOF.encode('ascii'), self.timeout)
            value = bytes(value).decode()

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return int(value.replace(self.EOF, ""))

  `def isconfigured(self, pin)`

    This function checks if the sysfs folder /sys/class/gpio/gpioNN exists.

    Shell:

        find /sys/class/gpio -name gpio14

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')

        led.configure(14, telnetio.RaspberryPi.OUTPUT)
        if led.isconfigured(14):
            print("LED is configured!!!")
        ...

    Source code

        def isconfigured(self, pin):
            """
            This function checks if the sysfs folder /sys/class/gpio/gpioNN exists.

            ***Shell:***
            ```shell
            find /sys/class/gpio -name gpio14
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.configure(14, telnetio.RaspberryPi.OUTPUT)
            if led.isconfigured(14):
                print("LED is configured!!!")
            ...
            ```
            """

            # Dictionary to transform mode strings to integers
            modes = {
                "in": self.INPUT,
                "out": self.OUTPUT,
            }

            # GPIO to check
            iotag = self._iotag + str(pin)

            # Check if pin folder is exported
            # find /sys/class/gpio -name gpio14
            command = "find " + \
                      "/sys/class/gpio " + \
                      "-name gpio[0-9][0-9]" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command response
            result = self.read_until(self.shell_prompt, self.timeout)
            result = bytes(result).decode()
            result = result.split(self.EOF)

            # Evaluate result in case sysfs folder exists
            if any(iotag in folders for folders in result):

                # Command to open file
                # sudo cat /sys/class/gpio/gpio14/direction
                command = "sudo cat " + \
                           "/sys/class/gpio/" + \
                           iotag + "/" + \
                           "direction" + \
                           self.EOF

                self.write(command.encode('ascii'))

                # Flush command echo
                self.read_until(self.EOF.encode('ascii'), self.timeout)

                # Read command result
                val = self.read_until(self.shell_prompt, self.timeout)
                val = bytes(val).decode()
                val = val.split()
                val = val[0].replace(self.EOF, "")
                val = val.lower()
                val = modes.get(val)

            else:
                val = 0

            return val

  `def islocked(self, pin)`

    Check if pin is already locked by an object of this class and returns the identification number of the locking process.

    Shell:

        sudo cat /tmp/htp/locks/gpio14

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')
        led.lock(14)
        if led.islocked(14) :
            print("LED is locked!!!")
        ...

    Source code

        def islocked(self, pin):
            """
            Check if pin is already locked by an object of this class and returns
            the identification number of the locking process.

            *** Shell: ***
            ```
            sudo cat /tmp/htp/locks/gpio14
            ```

            *** Example: ***
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')
            led.lock(14)
            if led.islocked(14) :
                print("LED is locked!!!")
            ...
            ```
            """

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            # GPIO lock file
            iotag = self._iotag + str(pin)
            lockfile = (self._lockdir + iotag)

            # Command to open file
            command = "sudo cat " + \
                      lockfile + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush command echo
            self.read_until(self.EOF.encode('ascii'), self.timeout)

            # Read command result
            result = self.read_until(self.shell_prompt, self.timeout)
            result = bytes(result).decode()
            result = result.split()
            result = result[0].replace(self.EOF, "")

            # Verify result (should be a number)
            try:
                int(result)
            except ValueError:
                result = None

            return result

  `def lock(self, pin)`

    Throws an exception PinLockedByOtherProcess or opens the gpio lock file and writes the session id in it.

    Shell:

        echo 1921681993055555 | sudo tee /tmp/htp/gpio14

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')
        led.lock(14)
        ...

    Source code

        def lock(self, pin):
            """
            Throws an exception <b>PinLockedByOtherProcess</b> or opens the gpio
            lock file and writes the session id in it.

            ***Shell***:
            ```shell
            echo 1921681993055555 | sudo tee /tmp/htp/gpio14
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')
            led.lock(14)
            ...
            ```
            """

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            # GPIO lock file
            iotag = self._iotag + str(pin)
            lockfile = self._lockdir + iotag

            # Create lock file
            lock_owner = self.islocked(pin)
            if lock_owner is not None:
                raise PinLockedByOtherProcess(lock_owner, self._session)
            else:
                command = "echo " + \
                          self._session + \
                          " | sudo tee " + \
                          lockfile + \
                          self.EOF

                self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

  `def login(self)`

    Performs an automatic login to the remote system using the supplied user and password as instance properties.

    !!! Use only when creating an unconnected instance !!!

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi()
        led.host = '192.168.199.31'
        led.port = 23
        led.user = 'htpio'
        led.password = 'sokotnar'

        led.open(host, port)
        led.login()

        ...

    Source code

        def login(self):
            """
            Performs an automatic login to the remote system using the supplied
            user and password as instance properties.

            !!! Use only when creating an unconnected instance !!!

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi()
            led.host = '192.168.199.31'
            led.port = 23
            led.user = 'htpio'
            led.password = 'sokotnar'

            led.open(host, port)
            led.login()

            ...
            ```
            """

            # Check if device already registered for use
            if not self._session:

                # Flush buffer and wait for login
                self.read_until(self.login_prompt, self.timeout)
                command = self.user + self.EOF
                self.write(command.encode('ascii'))

                # Flush buffer and wait for password
                self.read_until(self.password_prompt, self.timeout)
                command = self.password + self.EOF
                self.write(command.encode('ascii'))

                # Flush buffer
                result = self.read_until(self.shell_prompt, self.timeout)
                result = bytes(result).decode()

                if any('incorrect' in s for s in result.split()):
                    raise InvalidLoginDetails
                else:
                    self._session = self.__session()
                    self.__makedir()

            return 0

  `def logout(self)`

    Closes the connection to the target.

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')

        led.logout()

        ...

    Source code

        def logout(self):
            """
            Closes the connection to the target.

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.logout()

            ...
            ```
            """

            # Add additional steps before closing the connection
            self.close()

            return 0

  `def reset(self, pin)`

    Deletes lock file for pin.

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')

        led.reset(14)

        ...

    Source code

        def reset(self, pin):
            """
            Deletes lock file for pin.

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.reset(14)

            ...
            ```
            """

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            iotag = self._iotag + str(pin)
            lockfile = self._lockdir + iotag

            # Delete lock file
            command = "sudo rm " + \
                      lockfile + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

  `def set(self, pin, value)`

    Sets the current value of the given pin by using the system file.

    Shell:

        echo 1 | sudo tee /sys/class/gpio/gpio14

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')

        led.configure(14, telnetio.RaspberryPi.OUTPUT)
        led.set(14, 1)
        ...

    Source code

        def set(self, pin, value):
            """
            Sets the current value of the given pin by using the system file.

            *** Shell: ***
            ```
            echo 1 | sudo tee /sys/class/gpio/gpio14
            ```

            *** Example: ***
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')

            led.configure(14, telnetio.RaspberryPi.OUTPUT)
            led.set(14, 1)
            ...
            ```
            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Write to the desired pin (virtual file "value")
            command = "echo " + \
                      str(value) + \
                      " | sudo tee /sys/class/gpio/gpio" + \
                      str(pin) + \
                      "/value" + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

  `def unlock(self, pin)`

    Unlocks the gpio by deleting the content of the lock file.

    Shell:

        sudo truncate --size=0 /tmp/htp/locks/gpio14

    Example:

        import htpio.telnetio as telnetio

        led = telnetio.RaspberryPi('192.168.199.31')
        led.unlock(14)
        ...

    Source code

        def unlock(self, pin, ):
            """
            Unlocks the gpio by deleting the content of the lock file.

            ***Shell***:
            ```shell
            sudo truncate --size=0 /tmp/htp/locks/gpio14
            ```

            ***Example***:
            ```python
            import htpio.telnetio as telnetio

            led = telnetio.RaspberryPi('192.168.199.31')
            led.unlock(14)
            ...
            ```

            """

            # Verify is pin is locked by other process
            lock_owner = self.islocked(pin)
            if lock_owner is not None and lock_owner != self._session:
                raise PinLockedByOtherProcess(lock_owner, self._session)

            # Consistent folder name
            if not self._lockdir.endswith("/"):
                self._lockdir = self._lockdir + "/"

            # GPIO lock file
            iotag = self._iotag + str(pin)
            lockfile = self._lockdir + iotag

            # Empty lock file
            command = "sudo truncate --size=0 " + \
                      lockfile + \
                      self.EOF

            self.write(command.encode('ascii'))

            # Flush buffer
            self.read_until(self.shell_prompt, self.timeout)

            return 0

  ### Inherited members

  - `Device`:
    - `INPUT`
    - `OUTPUT`