Exemplo n.º 1
0
    def test_client_server(self):

        ADDRESS = 'localhost:44818'

        try:

            # same instance used as server and client
            enip = EnipProtocol(
                protocol=TestEnipProtocol.CLIENT_SERVER_PROTOCOL)

            # read a multikey
            what = ('SENSOR1', 1)
            enip._receive(what, ADDRESS)

            # read a single key
            what = ('ACTUATOR1',)
            enip._receive(what, ADDRESS)

            # write a multikey
            what = ('SENSOR1', 1)
            for value in range(5):
                enip._send(what, value, ADDRESS)

            # write a single key
            what = ('ACTUATOR1',)
            for value in range(5):
                enip._send(what, value, ADDRESS)

            EnipProtocol._stop_server(enip._server_subprocess)

        except Exception as error:
            EnipProtocol._stop_server(enip._server_subprocess)
            print 'ERROR test_client_server: ', error
            assert False
Exemplo n.º 2
0
    def test_send_multikey(self):

        enip = EnipProtocol(
            protocol=TestEnipProtocol.CLIENT_PROTOCOL)

        ADDRESS = 'localhost:44818'  # TEST port
        TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT'))

        try:
            server = EnipProtocol._start_server(ADDRESS, TAGS)

            # write a multikey
            what = ('SENSOR1', 1)
            for value in range(5):
                enip._send(what, value, ADDRESS)

            # write a single key
            what = ('ACTUATOR1',)
            for value in range(5):
                enip._send(what, value, ADDRESS)

            EnipProtocol._stop_server(server)

        except Exception as error:
            EnipProtocol._stop_server(server)
            print 'ERROR test_send_multikey: ', error
            assert False
Exemplo n.º 3
0
    def test_send_multikey(self):

        enip = EnipProtocol(protocol=CLIENT_PROTOCOL)

        TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT'))
        cmd = EnipProtocol._start_server_cmd(tags=TAGS)
        try:
            server = subprocess.Popen(cmd, shell=False)

            # write a multikey
            what = ('SENSOR1', 1)
            address = 'localhost:44818'
            for value in range(5):
                enip._send(what, value, address)

            # write a single key
            what = ('ACTUATOR1', )
            address = 'localhost:44818'
            for value in range(5):
                enip._send(what, value, address)

            EnipProtocol._stop_server(server)

        except Exception as error:
            EnipProtocol._stop_server(server)
            print 'ERROR test_client: ', error
Exemplo n.º 4
0
    def test_client_server(self):

        try:
            enip = EnipProtocol(protocol=CLIENT_SERVER_PROTOCOL)

            # read a multikey
            what = ('SENSOR1', 1)
            address = 'localhost:44818'
            enip._receive(what, address)

            # read a single key
            what = ('ACTUATOR1', )
            address = 'localhost:44818'
            enip._receive(what, address)

            # write a multikey
            what = ('SENSOR1', 1)
            address = 'localhost:44818'
            for value in range(5):
                enip._send(what, value, address)

            # write a single key
            what = ('ACTUATOR1', )
            address = 'localhost:44818'
            for value in range(5):
                enip._send(what, value, address)

            EnipProtocol._stop_server(enip._server_subprocess)

        except Exception as error:
            EnipProtocol._stop_server(enip._server_subprocess)
            print 'ERROR test_client_server: ', error
Exemplo n.º 5
0
class Device(object):

    """Base class."""

    # TODO: state dict convention (eg: multiple table support?)
    def __init__(self, name, protocol, state, disk={}, memory={}):
        """

        :param str name: device name
        :param dict protocol: used to set up the network layer API
        :param dict state: used to set up the physical layer API
        :param dict disk: persistent memory
        :param dict memory: main memory

        Device construction example:

        >>> device = Device(
        >>>     name='dev',
        >>>     protocol={
        >>>         'name': 'enip',
        >>>         'mode': 1,
        >>>         'server': {
        >>>             'address': '10.0.0.1',
        >>>             'tags': (('SENSOR1', 1), ('SENSOR2', 1)),
        >>>             }
        >>>     state={
        >>>         'path': '/path/to/db.sqlite',
        >>>         'name': 'table_name',
        >>>     }
        >>> )

        """

        self._validate_inputs(name, protocol, state, disk, memory)

        self.name = name
        self.state = state
        self.protocol = protocol
        self.memory = memory
        self.disk = disk

        self._init_state()
        self._init_protocol()
        self._start()
        self._stop()

    def _validate_inputs(self, name, protocol, state, disk, memory):

        # name string
        if type(name) is not str:
            raise TypeError('Name must be a string.')
        elif not name:
            raise ValueError('Name string cannot be empty.')

        # state dict
        if type(state) is not dict:
            raise TypeError('State must be a dict.')
        else:
            state_keys = state.keys()
            if (not state_keys) or (len(state_keys) != 2):
                raise KeyError('State must contain 2 keys.')
            else:
                for key in state_keys:
                    if (key != 'path') and (key != 'name'):
                        raise KeyError('%s is an invalid key.' % key)
            state_values = state.values()
            for val in state_values:
                if type(val) is not str:
                    raise TypeError('state values must be strings.')
            # state['path']
            subpath, extension = splitext(state['path'])
            # print 'DEBUG subpath: ', subpath
            # print 'DEBUG extension: ', extension
            if (extension != '.redis') and (extension != '.sqlite'):
                raise ValueError('%s extension not supported.' % extension)
            # state['name']
            if type(state['name']) is not str:
                raise TypeError('State name must be a string.')

        # protocol
        if type(protocol) is not dict:
            if protocol is not None:
                raise TypeError('Protocol must be either None or a dict.')
        else:
            protocol_keys = protocol.keys()
            if (not protocol_keys) or (len(protocol_keys) != 3):
                raise KeyError('Protocol must contain 3 keys.')
            else:
                for key in protocol_keys:
                    if ((key != 'name') and
                            (key != 'mode') and
                            (key != 'server')):
                        raise KeyError('%s is an invalid key.' % key)

            # protocol['name']
            if type(protocol['name']) is not str:
                raise TypeError('Protocol name must be a string.')
            else:
                name = protocol['name']
                if (name != 'enip'):
                    raise ValueError('%s protocol not supported.' % protocol)
            # protocol['mode']
            if type(protocol['mode']) is not int:
                raise TypeError('Protocol mode must be a int.')
            else:
                mode = protocol['mode']
                if (mode < 0):
                    raise ValueError('Protocol mode must be positive.')
            # protocol['server'] TODO
            # protocol['client'] TODO after adding it to the API

    def _init_state(self):
        """Bind device to the physical layer API."""

        subpath, extension = splitext(self.state['path'])

        if extension == '.sqlite':
            # TODO: add parametric value filed
            # print 'DEBUG state: ', self.state
            self._state = SQLiteState(self.state)
        elif extension == '.redis':
            # TODO: add parametric key serialization
            self._state = RedisState(self.state)
        else:
            print 'ERROR: %s backend not supported.' % self.state

    # TODO: add optional process name for the server and log location
    def _init_protocol(self):
        """Bind device to network API."""

        if self.protocol is None:
            print 'DEBUG: %s has no networking capabilities.' % self.name
            pass
        else:
            name = self.protocol['name']
            if name == 'enip':
                self._protocol = EnipProtocol(self.protocol)
            else:
                print 'ERROR: %s protocol not supported.' % self.protocol

    def _start(self):
        """Start a device."""

        print "TODO _start: please override me"

    def _stop(self):
        """Start a device."""

        print "TODO _stop: please override me"

    def set(self, what, value):
        """Set aka write a state value.

        :param tuple what: field[s] identifier[s]
        :param value: value to be setted

        :returns: setted value or ``TypeError`` if ``what`` is not a ``tuple``
        """

        if type(what) is not tuple:
            raise TypeError('Parameter must be a tuple.')
        else:
            return self._state._set(what, value)

    def get(self, what):
        """Get (read) a ``state`` value.

        :param tuple what: field[s] identifier[s]

        :returns: gotten value or ``TypeError`` if ``what`` is not a ``tuple``
        """

        if type(what) is not tuple:
            raise TypeError('Parameter must be a tuple.')
        else:
            return self._state._get(what)

    def send(self, what, value, address):
        """Send aka serve a value to another host.

        :param tuple what: field[s] identifier[s]
        :param value: value to be setted
        :param str address: ``ip[:port]``

        :returns: ``None`` or ``TypeError`` if ``what`` is not a ``tuple``
        """

        if type(what) is not tuple:
            raise TypeError('Parameter must be a tuple.')
        else:
            return self._protocol._send(what, value, address)

    def recieve(self, what, address):
        """Receive a value from another host.

        :param tuple what: field[s] identifier[s]
        :param str address: ``ip[:port]``

        :returns: recv value or ``TypeError`` if ``what`` is not a ``tuple``
        """

        if type(what) is not tuple:
            raise TypeError('Parameter must be a tuple.')
        else:
            return self._protocol._receive(what, address)