From 5560a1420969daa261ef2d8f3701107847483ad1 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 7 Apr 2017 18:09:19 +0800 Subject: [PATCH 01/31] added 2nd enip protocol api --- minicps/protocols.py | 225 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 222 insertions(+), 3 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index d7b6212..4f877c3 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -24,9 +24,10 @@ import shlex import subprocess -import cpppo -import pymodbus +from multiprocessing import Process +#import cpppo +#import pymodbus # Protocol {{{1 class Protocol(object): @@ -431,8 +432,226 @@ def _receive(self, what, address='localhost:44818', **kwargs): except Exception as error: print 'ERROR enip _receive: ', error -# }}} +class EnipProtocol(Protocol): + """EnipProtocol manager. + + EnipProtocol manages python enip library, Look at the original + documentation for more information. + + Tags are passed as a tuple of tuples, if the tuple contains only 1 tag + remember to put an ending comma, otherwise python will interpret the data + as a tuple and not as a tuple of tuples. + + eg: tag = (('SENSOR1'), ) + + Supported tag datatypes: + - SINT (8-bit) + - INT (16-bit) + - DINT (32-bit) + - REAL (32-bit float) + - BOOL (8-bit, bit #0) + - SSTRING[10] (simple string of 10 chars) # TODO: Not supported yet. + """ + + # server ports + _TCP_PORT = ':44818' + # _UDP_PORT = ':2222' # not supported + + def __init__(self, protocol): + + super(EnipProtocol, self).__init__(protocol) + + if sys.platform.startswith('linux'): + self._client_log = 'logs/enip_client ' + else: + raise OSError + + # tcp enip server + if self._mode == 1: + + # NOTE: set up logging + if sys.platform.startswith('linux'): + self._server_log = 'logs/enip_tcp_server ' + else: + raise OSError + + print 'DEBUG EnipProtocol server addr: ', self._server['address'] + if self._server['address'].find(':') == -1: + print 'DEBUG: concatenating server address with default port.' + self._server['address'] += EnipProtocol._TCP_PORT + + elif not self._server['address'].endswith(EnipProtocol._TCP_PORT): + print 'WARNING: not using std enip %s TCP port' % EnipProtocol._TCP_PORT + + self._server_subprocess = EnipProtocol._start_server( + address=self._server['address'], + tags=self._server['tags']) + + # TODO: udp enip server + elif self._mode == 2: pass + + @classmethod + def _tuple_to_enip_tags(cls, tag): + tag = [str(x) for x in tag] + return "{0}@{1}".format(':'.join(tag[:-1]), tag[-1]) + + @classmethod + def _nested_tuples_to_enip_tags(cls, tags): + """ Tuple to input format for server script init + :tags: ((SENSOR1, BOOL), (ACTUATOR1, 1, SINT), (TEMP2, REAL)) + :return: a string of the tuples (name and type separated by serializer) separated by white space + E.g. 'sensor1_BOOL actuator1:1_SINT temp2_REAL' + """ + tag_list = [cls._tuple_to_enip_tags(tag) for tag in tags] + return '--tags ' + ' '.join(tag_list) + + @classmethod + def _start_server_cmd(cls, address='localhost:44818', + tags=(('SENSOR1', 'INT'), ('ACTUATOR1', 'INT'))): + """Build a Popen cmd string for enip server. + + Tags can be any tuple of tuples. Each tuple has to contain a set of + string-convertible fields, the last one has to be a string containing + a supported datatype. The current serializer is : (colon). + + Consistency between enip server key-values and state key-values has to + be guaranteed by the client. + + :tags: to serve + :returns: cmd string passable to Popen object + """ + + if address.find(":") != -1: + address, port = address.split(":") + + if address == "localhost": address = "127.0.0.1" + + + VERBOSE = '-v ' + ADDRESS = '--address ' + address + ' ' + PORT = '--port ' + port + ' ' + TAGS = cls._nested_tuples_to_enip_tags(tags) + + ENV = "python3" + CMD = " /home/ahnafsidd/Github/enip-server/enipserver/server.py " + + if sys.platform.startswith('linux'): + LOG = '--log logs/protocols_tests_enip_server ' + else: + raise OSError + + cmd = shlex.split( + ENV + + CMD + + VERBOSE + + #LOG + + #ADDRESS + + TAGS + ) + print 'DEBUG enip _start_server cmd: ', cmd + + return cmd + + @classmethod + def _start_server(cls, address, tags): + """Start a enip server. + + Notice that the client has to manage the new process, + eg:kill it after use. + + :address: to serve + :tags: to serve + """ + try: + cmd = cls._start_server_cmd(address, tags) + cls.server = subprocess.Popen(cmd, shell=False) + + return cls.server + + except Exception as error: + print 'ERROR enip _start_server: ', error + + @classmethod + def _stop_server(cls, server): + """Stop an enip server. + + :server: Popen object + """ + try: + server.kill() + except Exception as error: + print 'ERROR stop enip server: ', error + + def _send(self, what, value, address='localhost', **kwargs): + """Send (serve) a value. + + It is a blocking operation the parent process will wait till the child + cpppo process returns. + + :what: tuple of (tag name, datatype) + :value: sent + :address: ip + """ + tag = self._tuple_to_enip_tags(what) + + ENV = "python " #sys.executable + CMD = "{0}pyenip/single_write.py ".format(self._minicps_path) + ADDRESS = "-i {0} ".format(address) + TAG = "-t {0} ".format(tag) + VAL = "-v {0}".format(value) + + cmd = shlex.split( + ENV + + CMD + + ADDRESS + + TAG + + VAL + ) + print 'DEBUG enip _start_server cmd: ', cmd + + try: + client = subprocess.Popen(cmd, shell=False) + client.wait() + + except Exception as error: + print 'ERROR enip _send: ', error + + def _receive(self, what, address='localhost'): + + """Receive a (requested) value. + + It is a blocking operation the parent process will wait till the child + cpppo process returns. + + :what: tag + :address: to receive from + + :returns: tuple of (value, datatype) + """ + tag_name = ':'.join([str(x) for x in what]) + + ENV = "python " #sys.executable + CMD = "{0}pyenip/single_read.py ".format(self._minicps_path) + ADDRESS = "-i {0} ".format(address) + TAG = "-t {0} ".format(tag_name) + + cmd = shlex.split( + ENV + + CMD + + ADDRESS + + TAG + ) + print 'DEBUG enip _start_server cmd: ', cmd + + try: + client = subprocess.Popen(cmd, shell=False) + client.wait() + + except Exception as error: + print 'ERROR enip _receive: ', error + +# }}} # ModbusProtocol {{{1 class ModbusProtocol(Protocol): From 3a3cd6203c208222418ab23d6102d870848d8120 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 7 Apr 2017 18:10:15 +0800 Subject: [PATCH 02/31] added test cases which can write to server --- tests/protocols_tests.py | 43 ++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index 762c17e..a5b3509 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -8,8 +8,8 @@ import shlex import time -import pymodbus -import cpppo +#import pymodbus +#import cpppo from minicps.protocols import Protocol, EnipProtocol, ModbusProtocol @@ -108,19 +108,23 @@ def test_send_multikey(self): try: server = EnipProtocol._start_server(ADDRESS, TAGS) - + time.sleep(1) # wait for the server to actually start so client can connect # write a multikey - what = ('SENSOR1', 1) + what = ('SENSOR1', 1, 'INT') # added type here for value in range(5): enip._send(what, value, ADDRESS) # write a single key - what = ('ACTUATOR1',) + what = ('ACTUATOR1', 'INT') for value in range(5): - enip._send(what, value, ADDRESS) + enip._send(what, 1, ADDRESS) - EnipProtocol._stop_server(server) + # write a single key + what = ('HMI_TEST101', 'REAL') + for value in range(5): + enip._send(what, 1, ADDRESS) + EnipProtocol._stop_server(server) except Exception as error: EnipProtocol._stop_server(server) print 'ERROR test_send_multikey: ', error @@ -136,6 +140,7 @@ def test_receive_multikey(self): try: server = EnipProtocol._start_server(ADDRESS, TAGS) + time.sleep(1) # wait for the server to actually start so client can connect # read a multikey what = ('SENSOR1', 1) @@ -147,6 +152,11 @@ def test_receive_multikey(self): address = 'localhost:44818' enip._receive(what, ADDRESS) + # Read a single key - present tag + what = ('HMI_TEST101',) + address = 'localhost:44818' + enip._receive(what, ADDRESS) + EnipProtocol._stop_server(server) except Exception as error: @@ -164,6 +174,8 @@ def test_client_server(self): enip = EnipProtocol( protocol=TestEnipProtocol.CLIENT_SERVER_PROTOCOL) + time.sleep(1) # wait for the server to actually start so client can connect + # read a multikey what = ('SENSOR1', 1) enip._receive(what, ADDRESS) @@ -172,13 +184,22 @@ def test_client_server(self): what = ('ACTUATOR1',) enip._receive(what, ADDRESS) + # read a single key - present tag + what = ('HMI_TEST101',) + enip._receive(what, ADDRESS) + # write a multikey - what = ('SENSOR1', 1) + what = ('SENSOR1', 1, 'INT') # added type here for value in range(5): enip._send(what, value, ADDRESS) # write a single key - what = ('ACTUATOR1',) + what = ('ACTUATOR1', 'INT') # added type here + for value in range(5): + enip._send(what, value, ADDRESS) + + # write a single key - present + what = ('HMI_TEST101', 'REAL') # added type here for value in range(5): enip._send(what, value, ADDRESS) @@ -197,7 +218,7 @@ def test_server_udp(self): # }}} -# TestModbusProtocol {{{1 +# # TestModbusProtocol {{{1 class TestModbusProtocol(): # NOTE: current API specifies only the number of tags @@ -475,4 +496,4 @@ def test_client_server_count(self): ModbusProtocol._stop_server(server) print 'ERROR test_client_server_count: ', error assert False -# }}} +# # }}} From 12e4b1e8c68e487a85be2d50dec720dd5d31cfac Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 7 Apr 2017 18:10:53 +0800 Subject: [PATCH 03/31] helper pyenip files based on pycomm to enable single tag read and write operations --- minicps/pyenip/single_read.py | 54 ++++++++++++++++++++++++++++ minicps/pyenip/single_write.py | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100755 minicps/pyenip/single_read.py create mode 100755 minicps/pyenip/single_write.py diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py new file mode 100755 index 0000000..526a002 --- /dev/null +++ b/minicps/pyenip/single_read.py @@ -0,0 +1,54 @@ +#!/usr/bin/python2 +""" +synch-client.py + +value is passed either as a ``str`` or as a ``bool``. In case of ``str`` the value is +converted to an ``int`` to be written in a holding register +""" + +import argparse # TODO: check if it is too slow at runtime +from pycomm.ab_comm.clx import Driver as ClxDriver + +def read_tag(address, tag_name): + plc = ClxDriver() + try: + if plc.open(address): + tagg = plc.read_tag(tag_name) + plc.close() + return (tagg) + else: + return ("u", ) + except Exception as e: + return ("e",) + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + + parser.add_argument('-i', type=str, dest='ip', required=True, + help='request ip') + + parser.add_argument('-t', '--tag', type=str, dest='tag', required=True, + help='request tag with type') + + args = parser.parse_args() + + # split tags if possible to retrieve name + tag_name = args.tag.split("@")[0] + + # retrieve the ip and ignore the port + address = args.ip.split(":")[0] + + res = read_tag(address, tag_name) + + val = res[0] + + if val == "e": + print("Unable to open connection at : {}".format(address)) + elif val == "u": + print("Unknown Error! Please check server log.") + elif val == False: + print("Read unsuccesful. Please check server log.") + else: + print("Success! Value: {0} for Tag: {1}. Type: {2}".format(val, tag_name, res[1])) + diff --git a/minicps/pyenip/single_write.py b/minicps/pyenip/single_write.py new file mode 100755 index 0000000..6804407 --- /dev/null +++ b/minicps/pyenip/single_write.py @@ -0,0 +1,65 @@ +#!/usr/bin/python2 + +""" +single_write.py + +value is passed as a ``str`` +""" + +import argparse # TODO: check if it is too slow at runtime +from pycomm.ab_comm.clx import Driver as ClxDriver + +def convert_value_to_type(tag_type, val): + if tag_type == "INT" or tag_type == "DINT" or tag_type == "SINT": value = int(val) + elif tag_type == "REAL": value = float(val) + elif tag_type == "BOOL": value = bool(val) + else: value = str(val) + return value + +def write_tag(tag_name, value, tag_type): + plc = ClxDriver() + try: + if plc.open(address): + temp = plc.write_tag(tag_name, value, tag_type) + plc.close() + return temp + else: + return "u" + except Exception as e: + return "e" + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + + parser.add_argument('-i', type=str, dest='ip', required=True, + help='request ip') + + parser.add_argument('-t', '--tag', type=str, dest='tag', required=True, + help='request tag with type') + + parser.add_argument('-v', '--val', type=str, dest='val', required=True, + help='value to be written') + + args = parser.parse_args() + + # split tags to retrieve type + tag_name, tag_type = args.tag.split("@") + + # retrieve the ip and ignore the port + address = args.ip.split(":")[0] + + value = convert_value_to_type(tag_type, args.val) + + res = write_tag(tag_name, value, tag_type) + + if res == "e": + print("Unable to open connection at : {}".format(address)) + elif res: + print("Successfully written value: {0} for tag: {1}".format(value, tag_name)) + else: + print("Write unsuccesful. Please check server log.") + + + + From 5a86bc4388a17e913ccdeee4e63037a40599dbc3 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 7 Apr 2017 18:23:41 +0800 Subject: [PATCH 04/31] commented old enipprotocol to keep both --- minicps/protocols.py | 547 +++++++++++++++++++++---------------------- 1 file changed, 271 insertions(+), 276 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index 4f877c3..f488c9b 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -127,7 +127,6 @@ def _send_multiple(self, what, values, address): # }}} # EnipProtocol {{{1 - # TODO: support vectorial tags def, read and write # int def: SCADA=INT[3] # int read: SCADA[0-3] @@ -135,302 +134,302 @@ def _send_multiple(self, what, values, address): # string def: TEXT=SSTRING[30] # string read: TEXT # string write: 'TEXT[0]=(SSTRING)"Hello world"' -class EnipProtocol(Protocol): - - """EnipProtocol manager. - - name: enip - - EnipProtocol manages python cpppo library, Look at the original - documentation for more information. - - Tags are passed as a tuple of tuples, if the tuple contains only 1 tag - remember to put an ending comma, otherwise python will interpret the data - as a tuple and not as a tuple of tuples. - - eg: tag = (('SENSOR1'), ) - - Supported modes: - - 0: client only - - 1: tcp enip server - - Supported tag data types: - - SINT (8-bit) - - INT (16-bit) - - DINT (32-bit) - - REAL (32-bit float) - - BOOL (8-bit, bit #0) - - SSTRING[10] (simple string of 10 chars) - """ - - # server ports - _TCP_PORT = ':44818' - _UDP_PORT = ':2222' - - def __init__(self, protocol): - - super(EnipProtocol, self).__init__(protocol) - - self._client_cmd = sys.executable + ' -m cpppo.server.enip.client ' - - # NOTE: set up logging - if sys.platform.startswith('linux'): - self._client_log = 'logs/enip_client ' - else: - raise OSError - - # tcp enip server - if self._mode == 1: - - # NOTE: set up logging - if sys.platform.startswith('linux'): - self._server_log = 'logs/enip_tcp_server ' - else: - raise OSError - - print 'DEBUG EnipProtocol server addr: ', self._server['address'] - if self._server['address'].find(':') == -1: - print 'DEBUG: concatenating server address with default port.' - self._server['address'] += EnipProtocol._TCP_PORT - elif not self._server['address'].endswith(EnipProtocol._TCP_PORT): - print 'WARNING: not using std enip %s TCP port' % \ - EnipProtocol._TCP_PORT +# class EnipProtocol(Protocol): +# """EnipProtocol manager. - self._server_cmd = sys.executable + ' -m cpppo.server.enip ' +# name: enip - self._server_subprocess = EnipProtocol._start_server( - address=self._server['address'], - tags=self._server['tags']) +# EnipProtocol manages python cpppo library, Look at the original +# documentation for more information. - # TODO: udp enip server - elif self._mode == 2: +# Tags are passed as a tuple of tuples, if the tuple contains only 1 tag +# remember to put an ending comma, otherwise python will interpret the data +# as a tuple and not as a tuple of tuples. - # NOTE: set up logging - if sys.platform.startswith('linux'): - self._server_log = 'logs/enip_udp_server ' - else: - raise OSError +# eg: tag = (('SENSOR1'), ) - print 'DEBUG EnipProtocol server addr: ', self._server['address'] - if self._server['address'].find(':') == -1: - print 'DEBUG: concatenating server address with default port.' - self._server['address'] += EnipProtocol._UDP_PORT +# Supported modes: +# - 0: client only +# - 1: tcp enip server + +# Supported tag data types: +# - SINT (8-bit) +# - INT (16-bit) +# - DINT (32-bit) +# - REAL (32-bit float) +# - BOOL (8-bit, bit #0) +# - SSTRING[10] (simple string of 10 chars) +# """ + +# # server ports +# _TCP_PORT = ':44818' +# _UDP_PORT = ':2222' + +# def __init__(self, protocol): + +# super(EnipProtocol, self).__init__(protocol) + +# self._client_cmd = sys.executable + ' -m cpppo.server.enip.client ' + +# # NOTE: set up logging +# if sys.platform.startswith('linux'): +# self._client_log = 'logs/enip_client ' +# else: +# raise OSError + +# # tcp enip server +# if self._mode == 1: + +# # NOTE: set up logging +# if sys.platform.startswith('linux'): +# self._server_log = 'logs/enip_tcp_server ' +# else: +# raise OSError + +# print 'DEBUG EnipProtocol server addr: ', self._server['address'] +# if self._server['address'].find(':') == -1: +# print 'DEBUG: concatenating server address with default port.' +# self._server['address'] += EnipProtocol._TCP_PORT + +# elif not self._server['address'].endswith(EnipProtocol._TCP_PORT): +# print 'WARNING: not using std enip %s TCP port' % \ +# EnipProtocol._TCP_PORT + +# self._server_cmd = sys.executable + ' -m cpppo.server.enip ' + +# self._server_subprocess = EnipProtocol._start_server( +# address=self._server['address'], +# tags=self._server['tags']) - elif not self._server['address'].endswith(EnipProtocol._UDP_PORT): - print 'WARNING: not using std enip %s UDP port' % \ - EnipProtocol._UDP_PORT - # TODO: add --udp flag - self._server_cmd = sys.executable + ' -m cpppo.server.enip ' - if sys.platform.startswith('linux'): - self._server_log = 'logs/enip_udp_server ' - else: - raise OSError +# # TODO: udp enip server +# elif self._mode == 2: - # TODO: start UDP enip server +# # NOTE: set up logging +# if sys.platform.startswith('linux'): +# self._server_log = 'logs/enip_udp_server ' +# else: +# raise OSError + +# print 'DEBUG EnipProtocol server addr: ', self._server['address'] +# if self._server['address'].find(':') == -1: +# print 'DEBUG: concatenating server address with default port.' +# self._server['address'] += EnipProtocol._UDP_PORT - @classmethod - def _tuple_to_cpppo_tag(cls, what, value=None, serializer=':'): - """Returns a cpppo string to read/write a server. +# elif not self._server['address'].endswith(EnipProtocol._UDP_PORT): +# print 'WARNING: not using std enip %s UDP port' % \ +# EnipProtocol._UDP_PORT +# # TODO: add --udp flag +# self._server_cmd = sys.executable + ' -m cpppo.server.enip ' +# if sys.platform.startswith('linux'): +# self._server_log = 'logs/enip_udp_server ' +# else: +# raise OSError + +# # TODO: start UDP enip server + +# @classmethod +# def _tuple_to_cpppo_tag(cls, what, value=None, serializer=':'): +# """Returns a cpppo string to read/write a server. + +# Can be used both to generate cpppo scalar read query, like +# SENSOR1:1, and scalar write query, like ACTUATOR1=1. + +# Value correctness is up the client and it is blindly +# converted to string and appended to the cpppo client query. +# """ + +# tag_string = '' +# tag_string += str(what[0]) + +# if len(what) > 1: +# for field in what[1:]: +# tag_string += EnipProtocol._SERIALIZER +# tag_string += str(field) +# if value is not None: +# if type(value) is str: +# # TODO: add support for SSTRING tags +# # ''' enip_client -a 192.168.1.20 'README:2[0]=(SSTRING)"string"' ''' +# pass +# tag_string += '=' +# tag_string += str(value) +# # print 'DEBUG _tuple_to_cpppo_tag tag_string: ', tag_string + +# return tag_string + +# @classmethod +# def _tuple_to_cpppo_tags(cls, tags, serializer=':'): +# """Returns a cpppo tags string to init a server. + +# cpppo API: SENSOR1=INT SENSOR2=REAL ACTUATOR1=INT +# """ + +# tags_string = '' +# for tag in tags: +# tags_string += str(tag[0]) +# for field in tag[1:-1]: +# tags_string += serializer +# # print 'DEBUG _tuple_to_cpppo_tags field: ', field +# tags_string += str(field) + +# tags_string += '=' +# tags_string += str(tag[-1]) +# tags_string += ' ' +# print 'DEBUG enip server tags_string: ', tags_string + +# return tags_string + +# @classmethod +# def _start_server(cls, address, tags): +# """Start a cpppo enip server. + +# The command used to start the server is generated by +# ``_start_server_cmd``. + +# Notice that the client has to manage the new process, +# eg:kill it after use. + +# :address: to serve +# :tags: to serve +# """ + +# try: +# cmd = EnipProtocol._start_server_cmd(address, tags) +# server = subprocess.Popen(cmd, shell=False) + +# return server + +# except Exception as error: +# print 'ERROR enip _start_server: ', error + +# # TODO: how to start a UDP cpppo server? +# # TODO: parametric PRINT_STDOUT and others +# @classmethod +# def _start_server_cmd(cls, address='localhost:44818', +# tags=(('SENSOR1', 'INT'), ('ACTUATOR1', 'INT'))): +# """Build a subprocess.Popen cmd string for cpppo server. + +# Tags can be any tuple of tuples. Each tuple has to contain a set of +# string-convertible fields, the last one has to be a string containing +# a supported datatype. The current serializer is : (colon). + +# Consistency between enip server key-values and state key-values has to +# be guaranteed by the client. + +# :address: to serve +# :tags: to serve + +# :returns: list of strings generated with shlex.split, +# passable to subprocess.Popen object +# """ + +# CMD = sys.executable + ' -m cpppo.server.enip ' +# PRINT_STDOUT = '--print ' +# HTTP = '--web %s:80 ' % address[0:address.find(':')] +# # print 'DEBUG: enip _start_server_cmd HTTP: ', HTTP +# ADDRESS = '--address ' + address + ' ' +# TAGS = EnipProtocol._tuple_to_cpppo_tags(tags) + +# if sys.platform.startswith('linux'): +# SHELL = '/bin/bash -c ' +# LOG = '--log logs/protocols_tests_enip_server ' +# else: +# raise OSError + +# cmd = shlex.split( +# CMD + +# PRINT_STDOUT + +# LOG + +# ADDRESS + +# TAGS +# ) +# print 'DEBUG enip _start_server cmd: ', cmd + +# return cmd + +# @classmethod +# def _stop_server(cls, server): +# """Stop an enip server. - Can be used both to generate cpppo scalar read query, like - SENSOR1:1, and scalar write query, like ACTUATOR1=1. +# :server: subprocess.Popen object +# """ - Value correctness is up the client and it is blindly - converted to string and appended to the cpppo client query. - """ +# try: +# server.kill() +# except Exception as error: +# print 'ERROR stop enip server: ', error - tag_string = '' - tag_string += str(what[0]) +# def _send(self, what, value, address='localhost:44818', **kwargs): +# """Send (write) a value to another host. - if len(what) > 1: - for field in what[1:]: - tag_string += EnipProtocol._SERIALIZER - tag_string += str(field) - if value is not None: - if type(value) is str: - # TODO: add support for SSTRING tags - # ''' enip_client -a 192.168.1.20 'README:2[0]=(SSTRING)"string"' ''' - pass - tag_string += '=' - tag_string += str(value) - # print 'DEBUG _tuple_to_cpppo_tag tag_string: ', tag_string +# It is a blocking operation the parent process will wait till the child +# cpppo process returns. + +# :what: tuple addressing what +# :value: sent +# :address: ip[:port] +# """ - return tag_string +# tag_string = '' +# tag_string = EnipProtocol._tuple_to_cpppo_tag(what, value) +# # print 'DEBUG enip _send tag_string: ', tag_string - @classmethod - def _tuple_to_cpppo_tags(cls, tags, serializer=':'): - """Returns a cpppo tags string to init a server. +# cmd = shlex.split( +# self._client_cmd + +# '--log ' + self._client_log + +# '--address ' + address + +# ' ' + tag_string +# ) +# # print 'DEBUG enip _send cmd shlex list: ', cmd - cpppo API: SENSOR1=INT SENSOR2=REAL ACTUATOR1=INT - """ +# # TODO: pipe stdout and return the sent value +# try: +# client = subprocess.Popen(cmd, shell=False) +# client.wait() - tags_string = '' - for tag in tags: - tags_string += str(tag[0]) - for field in tag[1:-1]: - tags_string += serializer - # print 'DEBUG _tuple_to_cpppo_tags field: ', field - tags_string += str(field) +# except Exception as error: +# print 'ERROR enip _send: ', error - tags_string += '=' - tags_string += str(tag[-1]) - tags_string += ' ' - print 'DEBUG enip server tags_string: ', tags_string +# def _receive(self, what, address='localhost:44818', **kwargs): +# """Receive (read) a value from another host. - return tags_string +# It is a blocking operation the parent process will wait till the child +# cpppo process returns. - @classmethod - def _start_server(cls, address, tags): - """Start a cpppo enip server. +# :what: to ask for +# :address: to receive from - The command used to start the server is generated by - ``_start_server_cmd``. +# :returns: tag value as a `str` +# """ - Notice that the client has to manage the new process, - eg:kill it after use. +# tag_string = '' +# tag_string = EnipProtocol._tuple_to_cpppo_tag(what) + +# cmd = shlex.split( +# self._client_cmd + +# '--log ' + self._client_log + +# '--address ' + address + +# ' ' + tag_string +# ) +# # print 'DEBUG enip _receive cmd shlex list: ', cmd - :address: to serve - :tags: to serve - """ +# try: +# client = subprocess.Popen(cmd, shell=False, +# stdout=subprocess.PIPE) + +# # client.communicate is blocking +# raw_out = client.communicate() +# # print 'DEBUG enip _receive raw_out: ', raw_out + +# # value is stored as first tuple element +# # between a pair of square brackets +# raw_string = raw_out[0] +# out = raw_string[(raw_string.find('[') + 1):raw_string.find(']')] - try: - cmd = EnipProtocol._start_server_cmd(address, tags) - server = subprocess.Popen(cmd, shell=False) +# return out - return server - - except Exception as error: - print 'ERROR enip _start_server: ', error - - # TODO: how to start a UDP cpppo server? - # TODO: parametric PRINT_STDOUT and others - @classmethod - def _start_server_cmd(cls, address='localhost:44818', - tags=(('SENSOR1', 'INT'), ('ACTUATOR1', 'INT'))): - """Build a subprocess.Popen cmd string for cpppo server. - - Tags can be any tuple of tuples. Each tuple has to contain a set of - string-convertible fields, the last one has to be a string containing - a supported datatype. The current serializer is : (colon). - - Consistency between enip server key-values and state key-values has to - be guaranteed by the client. - - :address: to serve - :tags: to serve - - :returns: list of strings generated with shlex.split, - passable to subprocess.Popen object - """ - - CMD = sys.executable + ' -m cpppo.server.enip ' - PRINT_STDOUT = '--print ' - HTTP = '--web %s:80 ' % address[0:address.find(':')] - # print 'DEBUG: enip _start_server_cmd HTTP: ', HTTP - ADDRESS = '--address ' + address + ' ' - TAGS = EnipProtocol._tuple_to_cpppo_tags(tags) - - if sys.platform.startswith('linux'): - SHELL = '/bin/bash -c ' - LOG = '--log logs/protocols_tests_enip_server ' - else: - raise OSError - - cmd = shlex.split( - CMD + - PRINT_STDOUT + - LOG + - ADDRESS + - TAGS - ) - print 'DEBUG enip _start_server cmd: ', cmd - - return cmd - - @classmethod - def _stop_server(cls, server): - """Stop an enip server. - - :server: subprocess.Popen object - """ - - try: - server.kill() - except Exception as error: - print 'ERROR stop enip server: ', error - - def _send(self, what, value, address='localhost:44818', **kwargs): - """Send (write) a value to another host. - - It is a blocking operation the parent process will wait till the child - cpppo process returns. - - :what: tuple addressing what - :value: sent - :address: ip[:port] - """ - - tag_string = '' - tag_string = EnipProtocol._tuple_to_cpppo_tag(what, value) - # print 'DEBUG enip _send tag_string: ', tag_string - - cmd = shlex.split( - self._client_cmd + - '--log ' + self._client_log + - '--address ' + address + - ' ' + tag_string - ) - # print 'DEBUG enip _send cmd shlex list: ', cmd - - # TODO: pipe stdout and return the sent value - try: - client = subprocess.Popen(cmd, shell=False) - client.wait() - - except Exception as error: - print 'ERROR enip _send: ', error - - def _receive(self, what, address='localhost:44818', **kwargs): - """Receive (read) a value from another host. - - It is a blocking operation the parent process will wait till the child - cpppo process returns. - - :what: to ask for - :address: to receive from - - :returns: tag value as a `str` - """ - - tag_string = '' - tag_string = EnipProtocol._tuple_to_cpppo_tag(what) - - cmd = shlex.split( - self._client_cmd + - '--log ' + self._client_log + - '--address ' + address + - ' ' + tag_string - ) - # print 'DEBUG enip _receive cmd shlex list: ', cmd - - try: - client = subprocess.Popen(cmd, shell=False, - stdout=subprocess.PIPE) - - # client.communicate is blocking - raw_out = client.communicate() - # print 'DEBUG enip _receive raw_out: ', raw_out - - # value is stored as first tuple element - # between a pair of square brackets - raw_string = raw_out[0] - out = raw_string[(raw_string.find('[') + 1):raw_string.find(']')] - - return out - - except Exception as error: - print 'ERROR enip _receive: ', error +# except Exception as error: +# print 'ERROR enip _receive: ', error class EnipProtocol(Protocol): @@ -525,9 +524,6 @@ def _start_server_cmd(cls, address='localhost:44818', if address.find(":") != -1: address, port = address.split(":") - if address == "localhost": address = "127.0.0.1" - - VERBOSE = '-v ' ADDRESS = '--address ' + address + ' ' PORT = '--port ' + port + ' ' @@ -650,7 +646,6 @@ def _receive(self, what, address='localhost'): except Exception as error: print 'ERROR enip _receive: ', error - # }}} # ModbusProtocol {{{1 From 0a691ede8b374ced3e1bbfdee0212e7757e3545d Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 7 Apr 2017 18:25:06 +0800 Subject: [PATCH 05/31] kept the old enipprotocol test cases but included the new one; old one is commented --- tests/protocols_tests.py | 176 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index a5b3509..fadb3d2 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -23,7 +23,181 @@ class TestProtocol(): # }}} -# TestEnipProtocol {{{1 +# # TestEnipProtocol {{{1 +# class TestEnipProtocol(): + +# # NOTE: second tuple element is the process id +# TAGS = ( +# ('SENSOR1', 1, 'INT'), +# ('SENSOR1', 2, 'INT'), +# ('ACTUATOR1', 'INT')) +# SERVER = { +# 'address': 'localhost:44818', +# 'tags': TAGS +# } +# CLIENT_SERVER_PROTOCOL = { +# 'name': 'enip', +# 'mode': 1, +# 'server': SERVER, +# } +# CLIENT_PROTOCOL = { +# 'name': 'enip', +# 'mode': 0, +# 'server': '', +# } +# if sys.platform.startswith('linux'): +# SHELL = '/bin/bash -c ' +# CLIENT_LOG = '--log logs/protocols_tests_enip_client ' +# else: +# raise OSError + +# def test_server_start_stop(self): + +# ADDRESS = 'localhost:44818' # TEST port +# TAGS = (('SENSOR1', 'INT'), ('ACTUATOR1', 'INT')) + +# try: +# server = EnipProtocol._start_server(ADDRESS, TAGS) +# EnipProtocol._stop_server(server) + +# except Exception as error: +# print 'ERROR test_server_start_stop: ', error +# assert False + +# def test_init_client(self): + +# try: +# client = EnipProtocol( +# protocol=TestEnipProtocol.CLIENT_PROTOCOL) +# eq_(client._name, 'enip') +# del client +# except Exception as error: +# print 'ERROR test_init_client: ', error +# assert False + +# def test_init_server(self): + +# try: +# server = EnipProtocol( +# protocol=TestEnipProtocol.CLIENT_SERVER_PROTOCOL) +# eq_(server._name, 'enip') +# server._stop_server(server._server_subprocess) +# del server +# except Exception as error: +# print 'ERROR test_init_server: ', error +# assert False + +# def test_server_multikey(self): + +# ADDRESS = 'localhost:44818' # TEST port +# TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT')) +# try: +# server = EnipProtocol._start_server(ADDRESS, TAGS) +# EnipProtocol._stop_server(server) +# except Exception as error: +# print 'ERROR test_server_multikey: ', error +# assert False + +# 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 + +# def test_receive_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) + +# # 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) + +# EnipProtocol._stop_server(server) + +# except Exception as error: +# EnipProtocol._stop_server(server) +# print 'ERROR test_receive_multikey: ', error +# assert False + +# 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 + +# @SkipTest +# def test_server_udp(self): + +# # TODO: implement it +# pass + +# # }}} + +# TestEnipProtocol 2 {{{1 class TestEnipProtocol(): # NOTE: second tuple element is the process id From f7f4e701abe7df4915d65cb52e00c8a8dfeef645 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Mon, 10 Apr 2017 10:25:22 +0800 Subject: [PATCH 06/31] remove old enip class; added logs and address as input arguments; added piping for process --- minicps/protocols.py | 329 +++---------------------------------------- 1 file changed, 22 insertions(+), 307 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index f488c9b..34f72fe 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -134,304 +134,6 @@ def _send_multiple(self, what, values, address): # string def: TEXT=SSTRING[30] # string read: TEXT # string write: 'TEXT[0]=(SSTRING)"Hello world"' - -# class EnipProtocol(Protocol): -# """EnipProtocol manager. - -# name: enip - -# EnipProtocol manages python cpppo library, Look at the original -# documentation for more information. - -# Tags are passed as a tuple of tuples, if the tuple contains only 1 tag -# remember to put an ending comma, otherwise python will interpret the data -# as a tuple and not as a tuple of tuples. - -# eg: tag = (('SENSOR1'), ) - -# Supported modes: -# - 0: client only -# - 1: tcp enip server - -# Supported tag data types: -# - SINT (8-bit) -# - INT (16-bit) -# - DINT (32-bit) -# - REAL (32-bit float) -# - BOOL (8-bit, bit #0) -# - SSTRING[10] (simple string of 10 chars) -# """ - -# # server ports -# _TCP_PORT = ':44818' -# _UDP_PORT = ':2222' - -# def __init__(self, protocol): - -# super(EnipProtocol, self).__init__(protocol) - -# self._client_cmd = sys.executable + ' -m cpppo.server.enip.client ' - -# # NOTE: set up logging -# if sys.platform.startswith('linux'): -# self._client_log = 'logs/enip_client ' -# else: -# raise OSError - -# # tcp enip server -# if self._mode == 1: - -# # NOTE: set up logging -# if sys.platform.startswith('linux'): -# self._server_log = 'logs/enip_tcp_server ' -# else: -# raise OSError - -# print 'DEBUG EnipProtocol server addr: ', self._server['address'] -# if self._server['address'].find(':') == -1: -# print 'DEBUG: concatenating server address with default port.' -# self._server['address'] += EnipProtocol._TCP_PORT - -# elif not self._server['address'].endswith(EnipProtocol._TCP_PORT): -# print 'WARNING: not using std enip %s TCP port' % \ -# EnipProtocol._TCP_PORT - -# self._server_cmd = sys.executable + ' -m cpppo.server.enip ' - -# self._server_subprocess = EnipProtocol._start_server( -# address=self._server['address'], -# tags=self._server['tags']) - -# # TODO: udp enip server -# elif self._mode == 2: - -# # NOTE: set up logging -# if sys.platform.startswith('linux'): -# self._server_log = 'logs/enip_udp_server ' -# else: -# raise OSError - -# print 'DEBUG EnipProtocol server addr: ', self._server['address'] -# if self._server['address'].find(':') == -1: -# print 'DEBUG: concatenating server address with default port.' -# self._server['address'] += EnipProtocol._UDP_PORT - -# elif not self._server['address'].endswith(EnipProtocol._UDP_PORT): -# print 'WARNING: not using std enip %s UDP port' % \ -# EnipProtocol._UDP_PORT -# # TODO: add --udp flag -# self._server_cmd = sys.executable + ' -m cpppo.server.enip ' -# if sys.platform.startswith('linux'): -# self._server_log = 'logs/enip_udp_server ' -# else: -# raise OSError - -# # TODO: start UDP enip server - -# @classmethod -# def _tuple_to_cpppo_tag(cls, what, value=None, serializer=':'): -# """Returns a cpppo string to read/write a server. - -# Can be used both to generate cpppo scalar read query, like -# SENSOR1:1, and scalar write query, like ACTUATOR1=1. - -# Value correctness is up the client and it is blindly -# converted to string and appended to the cpppo client query. -# """ - -# tag_string = '' -# tag_string += str(what[0]) - -# if len(what) > 1: -# for field in what[1:]: -# tag_string += EnipProtocol._SERIALIZER -# tag_string += str(field) -# if value is not None: -# if type(value) is str: -# # TODO: add support for SSTRING tags -# # ''' enip_client -a 192.168.1.20 'README:2[0]=(SSTRING)"string"' ''' -# pass -# tag_string += '=' -# tag_string += str(value) -# # print 'DEBUG _tuple_to_cpppo_tag tag_string: ', tag_string - -# return tag_string - -# @classmethod -# def _tuple_to_cpppo_tags(cls, tags, serializer=':'): -# """Returns a cpppo tags string to init a server. - -# cpppo API: SENSOR1=INT SENSOR2=REAL ACTUATOR1=INT -# """ - -# tags_string = '' -# for tag in tags: -# tags_string += str(tag[0]) -# for field in tag[1:-1]: -# tags_string += serializer -# # print 'DEBUG _tuple_to_cpppo_tags field: ', field -# tags_string += str(field) - -# tags_string += '=' -# tags_string += str(tag[-1]) -# tags_string += ' ' -# print 'DEBUG enip server tags_string: ', tags_string - -# return tags_string - -# @classmethod -# def _start_server(cls, address, tags): -# """Start a cpppo enip server. - -# The command used to start the server is generated by -# ``_start_server_cmd``. - -# Notice that the client has to manage the new process, -# eg:kill it after use. - -# :address: to serve -# :tags: to serve -# """ - -# try: -# cmd = EnipProtocol._start_server_cmd(address, tags) -# server = subprocess.Popen(cmd, shell=False) - -# return server - -# except Exception as error: -# print 'ERROR enip _start_server: ', error - -# # TODO: how to start a UDP cpppo server? -# # TODO: parametric PRINT_STDOUT and others -# @classmethod -# def _start_server_cmd(cls, address='localhost:44818', -# tags=(('SENSOR1', 'INT'), ('ACTUATOR1', 'INT'))): -# """Build a subprocess.Popen cmd string for cpppo server. - -# Tags can be any tuple of tuples. Each tuple has to contain a set of -# string-convertible fields, the last one has to be a string containing -# a supported datatype. The current serializer is : (colon). - -# Consistency between enip server key-values and state key-values has to -# be guaranteed by the client. - -# :address: to serve -# :tags: to serve - -# :returns: list of strings generated with shlex.split, -# passable to subprocess.Popen object -# """ - -# CMD = sys.executable + ' -m cpppo.server.enip ' -# PRINT_STDOUT = '--print ' -# HTTP = '--web %s:80 ' % address[0:address.find(':')] -# # print 'DEBUG: enip _start_server_cmd HTTP: ', HTTP -# ADDRESS = '--address ' + address + ' ' -# TAGS = EnipProtocol._tuple_to_cpppo_tags(tags) - -# if sys.platform.startswith('linux'): -# SHELL = '/bin/bash -c ' -# LOG = '--log logs/protocols_tests_enip_server ' -# else: -# raise OSError - -# cmd = shlex.split( -# CMD + -# PRINT_STDOUT + -# LOG + -# ADDRESS + -# TAGS -# ) -# print 'DEBUG enip _start_server cmd: ', cmd - -# return cmd - -# @classmethod -# def _stop_server(cls, server): -# """Stop an enip server. - -# :server: subprocess.Popen object -# """ - -# try: -# server.kill() -# except Exception as error: -# print 'ERROR stop enip server: ', error - -# def _send(self, what, value, address='localhost:44818', **kwargs): -# """Send (write) a value to another host. - -# It is a blocking operation the parent process will wait till the child -# cpppo process returns. - -# :what: tuple addressing what -# :value: sent -# :address: ip[:port] -# """ - -# tag_string = '' -# tag_string = EnipProtocol._tuple_to_cpppo_tag(what, value) -# # print 'DEBUG enip _send tag_string: ', tag_string - -# cmd = shlex.split( -# self._client_cmd + -# '--log ' + self._client_log + -# '--address ' + address + -# ' ' + tag_string -# ) -# # print 'DEBUG enip _send cmd shlex list: ', cmd - -# # TODO: pipe stdout and return the sent value -# try: -# client = subprocess.Popen(cmd, shell=False) -# client.wait() - -# except Exception as error: -# print 'ERROR enip _send: ', error - -# def _receive(self, what, address='localhost:44818', **kwargs): -# """Receive (read) a value from another host. - -# It is a blocking operation the parent process will wait till the child -# cpppo process returns. - -# :what: to ask for -# :address: to receive from - -# :returns: tag value as a `str` -# """ - -# tag_string = '' -# tag_string = EnipProtocol._tuple_to_cpppo_tag(what) - -# cmd = shlex.split( -# self._client_cmd + -# '--log ' + self._client_log + -# '--address ' + address + -# ' ' + tag_string -# ) -# # print 'DEBUG enip _receive cmd shlex list: ', cmd - -# try: -# client = subprocess.Popen(cmd, shell=False, -# stdout=subprocess.PIPE) - -# # client.communicate is blocking -# raw_out = client.communicate() -# # print 'DEBUG enip _receive raw_out: ', raw_out - -# # value is stored as first tuple element -# # between a pair of square brackets -# raw_string = raw_out[0] -# out = raw_string[(raw_string.find('[') + 1):raw_string.find(']')] - -# return out - -# except Exception as error: -# print 'ERROR enip _receive: ', error - - class EnipProtocol(Protocol): """EnipProtocol manager. @@ -522,15 +224,14 @@ def _start_server_cmd(cls, address='localhost:44818', """ if address.find(":") != -1: - address, port = address.split(":") + address = address.split(":")[0] VERBOSE = '-v ' ADDRESS = '--address ' + address + ' ' - PORT = '--port ' + port + ' ' TAGS = cls._nested_tuples_to_enip_tags(tags) ENV = "python3" - CMD = " /home/ahnafsidd/Github/enip-server/enipserver/server.py " + CMD = " -m enipserver.server " if sys.platform.startswith('linux'): LOG = '--log logs/protocols_tests_enip_server ' @@ -541,8 +242,8 @@ def _start_server_cmd(cls, address='localhost:44818', ENV + CMD + VERBOSE + - #LOG + - #ADDRESS + + LOG + + ADDRESS + TAGS ) print 'DEBUG enip _start_server cmd: ', cmd @@ -607,8 +308,15 @@ def _send(self, what, value, address='localhost', **kwargs): print 'DEBUG enip _start_server cmd: ', cmd try: - client = subprocess.Popen(cmd, shell=False) - client.wait() + client = subprocess.Popen(cmd, shell=False, + stdout=subprocess.PIPE) + + # client.communicate is blocking + raw_out = client.communicate() + print 'DEBUG enip _receive raw_out: ', raw_out + + #value is stored as first tuple element + return raw_out[0] except Exception as error: print 'ERROR enip _send: ', error @@ -641,8 +349,15 @@ def _receive(self, what, address='localhost'): print 'DEBUG enip _start_server cmd: ', cmd try: - client = subprocess.Popen(cmd, shell=False) - client.wait() + client = subprocess.Popen(cmd, shell=False, + stdout=subprocess.PIPE) + + # client.communicate is blocking + raw_out = client.communicate() + print 'DEBUG enip _receive raw_out: ', raw_out + + #value is stored as first tuple element + return raw_out[0] except Exception as error: print 'ERROR enip _receive: ', error From b0a09e4a79ad7e88fd8ac89780b6bb47b87c0d4b Mon Sep 17 00:00:00 2001 From: ahnaf Date: Mon, 10 Apr 2017 10:25:49 +0800 Subject: [PATCH 07/31] removed old enip class test --- tests/protocols_tests.py | 632 ++++++++++++++------------------------- 1 file changed, 229 insertions(+), 403 deletions(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index fadb3d2..9218785 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -24,180 +24,6 @@ class TestProtocol(): # }}} # # TestEnipProtocol {{{1 -# class TestEnipProtocol(): - -# # NOTE: second tuple element is the process id -# TAGS = ( -# ('SENSOR1', 1, 'INT'), -# ('SENSOR1', 2, 'INT'), -# ('ACTUATOR1', 'INT')) -# SERVER = { -# 'address': 'localhost:44818', -# 'tags': TAGS -# } -# CLIENT_SERVER_PROTOCOL = { -# 'name': 'enip', -# 'mode': 1, -# 'server': SERVER, -# } -# CLIENT_PROTOCOL = { -# 'name': 'enip', -# 'mode': 0, -# 'server': '', -# } -# if sys.platform.startswith('linux'): -# SHELL = '/bin/bash -c ' -# CLIENT_LOG = '--log logs/protocols_tests_enip_client ' -# else: -# raise OSError - -# def test_server_start_stop(self): - -# ADDRESS = 'localhost:44818' # TEST port -# TAGS = (('SENSOR1', 'INT'), ('ACTUATOR1', 'INT')) - -# try: -# server = EnipProtocol._start_server(ADDRESS, TAGS) -# EnipProtocol._stop_server(server) - -# except Exception as error: -# print 'ERROR test_server_start_stop: ', error -# assert False - -# def test_init_client(self): - -# try: -# client = EnipProtocol( -# protocol=TestEnipProtocol.CLIENT_PROTOCOL) -# eq_(client._name, 'enip') -# del client -# except Exception as error: -# print 'ERROR test_init_client: ', error -# assert False - -# def test_init_server(self): - -# try: -# server = EnipProtocol( -# protocol=TestEnipProtocol.CLIENT_SERVER_PROTOCOL) -# eq_(server._name, 'enip') -# server._stop_server(server._server_subprocess) -# del server -# except Exception as error: -# print 'ERROR test_init_server: ', error -# assert False - -# def test_server_multikey(self): - -# ADDRESS = 'localhost:44818' # TEST port -# TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT')) -# try: -# server = EnipProtocol._start_server(ADDRESS, TAGS) -# EnipProtocol._stop_server(server) -# except Exception as error: -# print 'ERROR test_server_multikey: ', error -# assert False - -# 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 - -# def test_receive_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) - -# # 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) - -# EnipProtocol._stop_server(server) - -# except Exception as error: -# EnipProtocol._stop_server(server) -# print 'ERROR test_receive_multikey: ', error -# assert False - -# 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 - -# @SkipTest -# def test_server_udp(self): - -# # TODO: implement it -# pass - -# # }}} - -# TestEnipProtocol 2 {{{1 class TestEnipProtocol(): # NOTE: second tuple element is the process id @@ -393,281 +219,281 @@ def test_server_udp(self): # }}} # # TestModbusProtocol {{{1 -class TestModbusProtocol(): - - # NOTE: current API specifies only the number of tags - TAGS = (200, 200, 200, 200) - # TAGS = ( - # ('CO1', 1, 'CO'), - # ('CO1', 2, 'CO'), - # ('DI1', 1, 'DI'), - # ('DI1', 2, 'DI'), - # ('HR1', 1, 'HR'), - # ('HR2', 2, 'HR'), - # ('IR1', 1, 'IR'), - # ('IR2', 4, 'IR')) - SERVER = { - 'address': 'localhost:502', - 'tags': TAGS - } - CLIENT_SERVER_PROTOCOL = { - 'name': 'modbus', - 'mode': 1, - 'server': SERVER, - } - CLIENT_PROTOCOL = { - 'name': 'modbus', - 'mode': 0, - 'server': '', - } - if sys.platform.startswith('linux'): - SHELL = '/bin/bash -c ' - CLIENT_LOG = '--log logs/protocols_tests_modbus_client ' - else: - raise OSError +# class TestModbusProtocol(): + +# # NOTE: current API specifies only the number of tags +# TAGS = (200, 200, 200, 200) +# # TAGS = ( +# # ('CO1', 1, 'CO'), +# # ('CO1', 2, 'CO'), +# # ('DI1', 1, 'DI'), +# # ('DI1', 2, 'DI'), +# # ('HR1', 1, 'HR'), +# # ('HR2', 2, 'HR'), +# # ('IR1', 1, 'IR'), +# # ('IR2', 4, 'IR')) +# SERVER = { +# 'address': 'localhost:502', +# 'tags': TAGS +# } +# CLIENT_SERVER_PROTOCOL = { +# 'name': 'modbus', +# 'mode': 1, +# 'server': SERVER, +# } +# CLIENT_PROTOCOL = { +# 'name': 'modbus', +# 'mode': 0, +# 'server': '', +# } +# if sys.platform.startswith('linux'): +# SHELL = '/bin/bash -c ' +# CLIENT_LOG = '--log logs/protocols_tests_modbus_client ' +# else: +# raise OSError - from minicps import __file__ as minicps_path - minicps_path = minicps_path[:-12] - SERVER_CMD_PATH = sys.executable + ' ' + minicps_path + \ - 'pymodbus/servers.py ' # NOTE: ending whitespace +# from minicps import __file__ as minicps_path +# minicps_path = minicps_path[:-12] +# SERVER_CMD_PATH = sys.executable + ' ' + minicps_path + \ +# 'pymodbus/servers.py ' # NOTE: ending whitespace - def test_server_start_stop(self): +# def test_server_start_stop(self): - try: - server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, - 'localhost:502', self.TAGS) - ModbusProtocol._stop_server(server) +# try: +# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, +# 'localhost:502', self.TAGS) +# ModbusProtocol._stop_server(server) - except Exception as error: - print 'ERROR test_server_start_stop: ', error - assert False +# except Exception as error: +# print 'ERROR test_server_start_stop: ', error +# assert False - def test_init_client(self): +# def test_init_client(self): - try: - client = ModbusProtocol( - protocol=TestModbusProtocol.CLIENT_PROTOCOL) - eq_(client._name, 'modbus') - del client +# try: +# client = ModbusProtocol( +# protocol=TestModbusProtocol.CLIENT_PROTOCOL) +# eq_(client._name, 'modbus') +# del client - except Exception as error: - print 'ERROR test_init_client: ', error - assert False +# except Exception as error: +# print 'ERROR test_init_client: ', error +# assert False - def test_init_server(self): +# def test_init_server(self): - try: - server = ModbusProtocol( - protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) - eq_(server._name, 'modbus') - server._stop_server(server._server_subprocess) - del server +# try: +# server = ModbusProtocol( +# protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) +# eq_(server._name, 'modbus') +# server._stop_server(server._server_subprocess) +# del server - except Exception as error: - print 'ERROR test_init_server: ', error - assert False +# except Exception as error: +# print 'ERROR test_init_server: ', error +# assert False - def test_send(self): +# def test_send(self): - client = ModbusProtocol( - protocol=TestModbusProtocol.CLIENT_PROTOCOL) +# client = ModbusProtocol( +# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - ADDRESS = 'localhost:502' - TAGS = (20, 20, 20, 20) - OFFSET = 10 +# ADDRESS = 'localhost:502' +# TAGS = (20, 20, 20, 20) +# OFFSET = 10 - try: - server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) - time.sleep(1.0) +# try: +# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) +# time.sleep(1.0) - print('TEST: Write to holding registers') - for offset in range(0, OFFSET): - what = ('HR', offset) - client._send(what, offset, ADDRESS) - print('') +# print('TEST: Write to holding registers') +# for offset in range(0, OFFSET): +# what = ('HR', offset) +# client._send(what, offset, ADDRESS) +# print('') - coil = True - print('TEST: Write to coils') - for offset in range(0, OFFSET): - what = ('CO', offset) - client._send(what, coil, ADDRESS) - coil = not coil - print('') +# coil = True +# print('TEST: Write to coils') +# for offset in range(0, OFFSET): +# what = ('CO', offset) +# client._send(what, coil, ADDRESS) +# coil = not coil +# print('') - ModbusProtocol._stop_server(server) +# ModbusProtocol._stop_server(server) - except Exception as error: - ModbusProtocol._stop_server(server) - print 'ERROR test_send: ', error - assert False +# except Exception as error: +# ModbusProtocol._stop_server(server) +# print 'ERROR test_send: ', error +# assert False - def test_receive(self): +# def test_receive(self): - client = ModbusProtocol( - protocol=TestModbusProtocol.CLIENT_PROTOCOL) +# client = ModbusProtocol( +# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - ADDRESS = 'localhost:502' - TAGS = (20, 20, 20, 20) - OFFSET = 10 +# ADDRESS = 'localhost:502' +# TAGS = (20, 20, 20, 20) +# OFFSET = 10 - try: - server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) - time.sleep(1.0) - - print('TEST: Read holding registers') - for offset in range(0, OFFSET): - what = ('HR', offset) - eq_(client._receive(what, ADDRESS), 0) - print('') - - print('TEST: Read input registers') - for offset in range(0, OFFSET): - what = ('IR', offset) - eq_(client._receive(what, ADDRESS), 0) - print('') - - print('TEST: Read discrete inputs') - for offset in range(0, OFFSET): - what = ('DI', offset) - eq_(client._receive(what, ADDRESS), False) - print('') - - print('TEST: Read coils inputs') - for offset in range(0, OFFSET): - what = ('CO', offset) - eq_(client._receive(what, ADDRESS), False) - print('') - - ModbusProtocol._stop_server(server) +# try: +# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) +# time.sleep(1.0) + +# print('TEST: Read holding registers') +# for offset in range(0, OFFSET): +# what = ('HR', offset) +# eq_(client._receive(what, ADDRESS), 0) +# print('') + +# print('TEST: Read input registers') +# for offset in range(0, OFFSET): +# what = ('IR', offset) +# eq_(client._receive(what, ADDRESS), 0) +# print('') + +# print('TEST: Read discrete inputs') +# for offset in range(0, OFFSET): +# what = ('DI', offset) +# eq_(client._receive(what, ADDRESS), False) +# print('') + +# print('TEST: Read coils inputs') +# for offset in range(0, OFFSET): +# what = ('CO', offset) +# eq_(client._receive(what, ADDRESS), False) +# print('') + +# ModbusProtocol._stop_server(server) - except Exception as error: - ModbusProtocol._stop_server(server) - print 'ERROR test_receive: ', error - assert False +# except Exception as error: +# ModbusProtocol._stop_server(server) +# print 'ERROR test_receive: ', error +# assert False - @SkipTest - def test_client_server(self): +# @SkipTest +# def test_client_server(self): - ADDRESS = 'localhost:502' +# ADDRESS = 'localhost:502' - try: - # NOTE: same instance used as server and client - modbus = ModbusProtocol( - protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) - time.sleep(1.0) - - print('TEST: Write and read coils') - what = ('CO', 0) - value = True - modbus._send(what, value, ADDRESS) - what = ('CO', 0) - eq_(modbus._receive(what, ADDRESS), True) - - what = ('CO', 1) - value = False - modbus._send(what, value, ADDRESS) - what = ('CO', 1) - eq_(modbus._receive(what, ADDRESS), False) - print('') - - print('TEST: Write and read holding registers') - for hr in range(10): - what = ('HR', hr) - modbus._send(what, hr, ADDRESS) - what = ('HR', hr) - eq_(modbus._receive(what, ADDRESS), hr) - print('') - - print('TEST: Read discrete inputs (init to False)') - what = ('DI', 0) - eq_(modbus._receive(what, ADDRESS), False) - print('') - - print('TEST: Read input registers (init to 0)') - for ir in range(10): - what = ('IR', ir) - eq_(modbus._receive(what, ADDRESS), 0) - print('') - - ModbusProtocol._stop_server(modbus._server_subprocess) +# try: +# # NOTE: same instance used as server and client +# modbus = ModbusProtocol( +# protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) +# time.sleep(1.0) + +# print('TEST: Write and read coils') +# what = ('CO', 0) +# value = True +# modbus._send(what, value, ADDRESS) +# what = ('CO', 0) +# eq_(modbus._receive(what, ADDRESS), True) + +# what = ('CO', 1) +# value = False +# modbus._send(what, value, ADDRESS) +# what = ('CO', 1) +# eq_(modbus._receive(what, ADDRESS), False) +# print('') + +# print('TEST: Write and read holding registers') +# for hr in range(10): +# what = ('HR', hr) +# modbus._send(what, hr, ADDRESS) +# what = ('HR', hr) +# eq_(modbus._receive(what, ADDRESS), hr) +# print('') + +# print('TEST: Read discrete inputs (init to False)') +# what = ('DI', 0) +# eq_(modbus._receive(what, ADDRESS), False) +# print('') + +# print('TEST: Read input registers (init to 0)') +# for ir in range(10): +# what = ('IR', ir) +# eq_(modbus._receive(what, ADDRESS), 0) +# print('') + +# ModbusProtocol._stop_server(modbus._server_subprocess) - except Exception as error: - ModbusProtocol._stop_server(modbus._server_subprocess) - print 'ERROR test_client_server: ', error - assert False +# except Exception as error: +# ModbusProtocol._stop_server(modbus._server_subprocess) +# print 'ERROR test_client_server: ', error +# assert False - def test_receive_count(self): +# def test_receive_count(self): - client = ModbusProtocol( - protocol=TestModbusProtocol.CLIENT_PROTOCOL) +# client = ModbusProtocol( +# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - ADDRESS = 'localhost:502' - TAGS = (20, 20, 20, 20) +# ADDRESS = 'localhost:502' +# TAGS = (20, 20, 20, 20) - try: - server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) - time.sleep(1.0) +# try: +# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) +# time.sleep(1.0) - print('TEST: Read holding registers, count=3') - what = ('HR', 0) - eq_(client._receive(what, ADDRESS, count=3), [0, 0, 0]) - print('') +# print('TEST: Read holding registers, count=3') +# what = ('HR', 0) +# eq_(client._receive(what, ADDRESS, count=3), [0, 0, 0]) +# print('') - print('TEST: Read input registers, count=1') - what = ('IR', 0) - eq_(client._receive(what, ADDRESS, count=1), 0) - print('') +# print('TEST: Read input registers, count=1') +# what = ('IR', 0) +# eq_(client._receive(what, ADDRESS, count=1), 0) +# print('') - print('TEST: Read discrete inputs, count=2') - what = ('DI', 0) - eq_(client._receive(what, ADDRESS, count=2), [False] * 2) - print('') +# print('TEST: Read discrete inputs, count=2') +# what = ('DI', 0) +# eq_(client._receive(what, ADDRESS, count=2), [False] * 2) +# print('') - print('TEST: Read coils, count=9') - what = ('CO', 0) - eq_(client._receive(what, ADDRESS, count=9), [False] * 9) - print('') +# print('TEST: Read coils, count=9') +# what = ('CO', 0) +# eq_(client._receive(what, ADDRESS, count=9), [False] * 9) +# print('') - ModbusProtocol._stop_server(server) +# ModbusProtocol._stop_server(server) - except Exception as error: - ModbusProtocol._stop_server(server) - print 'ERROR test_receive_count: ', error - assert False +# except Exception as error: +# ModbusProtocol._stop_server(server) +# print 'ERROR test_receive_count: ', error +# assert False - def test_client_server_count(self): +# def test_client_server_count(self): - client = ModbusProtocol( - protocol=TestModbusProtocol.CLIENT_PROTOCOL) +# client = ModbusProtocol( +# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - ADDRESS = 'localhost:502' - TAGS = (50, 50, 50, 50) +# ADDRESS = 'localhost:502' +# TAGS = (50, 50, 50, 50) - try: - server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) - time.sleep(1.0) +# try: +# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) +# time.sleep(1.0) - print('TEST: Write and Read holding registers, offset=4, count=3') - what = ('HR', 4) - hrs = [1, 2, 3] - client._send(what, hrs, ADDRESS, count=3) - eq_(client._receive(what, ADDRESS, count=3), hrs) - print('') +# print('TEST: Write and Read holding registers, offset=4, count=3') +# what = ('HR', 4) +# hrs = [1, 2, 3] +# client._send(what, hrs, ADDRESS, count=3) +# eq_(client._receive(what, ADDRESS, count=3), hrs) +# print('') - print('TEST: Write and Read holding registers, offset=4, count=3') - what = ('CO', 7) - cos = [True, False, False, True, False] - client._send(what, cos, ADDRESS, count=5) - eq_(client._receive(what, ADDRESS, count=5), cos) - print('') +# print('TEST: Write and Read holding registers, offset=4, count=3') +# what = ('CO', 7) +# cos = [True, False, False, True, False] +# client._send(what, cos, ADDRESS, count=5) +# eq_(client._receive(what, ADDRESS, count=5), cos) +# print('') - ModbusProtocol._stop_server(server) +# ModbusProtocol._stop_server(server) - except Exception as error: - ModbusProtocol._stop_server(server) - print 'ERROR test_client_server_count: ', error - assert False +# except Exception as error: +# ModbusProtocol._stop_server(server) +# print 'ERROR test_client_server_count: ', error +# assert False # # }}} From 0cf4321e8b0247c7d08d0faa6cb5faa98cf9a958 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Mon, 10 Apr 2017 10:26:31 +0800 Subject: [PATCH 08/31] uncommented modbus protocol test --- tests/protocols_tests.py | 554 +++++++++++++++++++-------------------- 1 file changed, 277 insertions(+), 277 deletions(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index 9218785..94a5926 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -219,281 +219,281 @@ def test_server_udp(self): # }}} # # TestModbusProtocol {{{1 -# class TestModbusProtocol(): - -# # NOTE: current API specifies only the number of tags -# TAGS = (200, 200, 200, 200) -# # TAGS = ( -# # ('CO1', 1, 'CO'), -# # ('CO1', 2, 'CO'), -# # ('DI1', 1, 'DI'), -# # ('DI1', 2, 'DI'), -# # ('HR1', 1, 'HR'), -# # ('HR2', 2, 'HR'), -# # ('IR1', 1, 'IR'), -# # ('IR2', 4, 'IR')) -# SERVER = { -# 'address': 'localhost:502', -# 'tags': TAGS -# } -# CLIENT_SERVER_PROTOCOL = { -# 'name': 'modbus', -# 'mode': 1, -# 'server': SERVER, -# } -# CLIENT_PROTOCOL = { -# 'name': 'modbus', -# 'mode': 0, -# 'server': '', -# } -# if sys.platform.startswith('linux'): -# SHELL = '/bin/bash -c ' -# CLIENT_LOG = '--log logs/protocols_tests_modbus_client ' -# else: -# raise OSError - -# from minicps import __file__ as minicps_path -# minicps_path = minicps_path[:-12] -# SERVER_CMD_PATH = sys.executable + ' ' + minicps_path + \ -# 'pymodbus/servers.py ' # NOTE: ending whitespace - -# def test_server_start_stop(self): - -# try: -# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, -# 'localhost:502', self.TAGS) -# ModbusProtocol._stop_server(server) - -# except Exception as error: -# print 'ERROR test_server_start_stop: ', error -# assert False - - -# def test_init_client(self): - -# try: -# client = ModbusProtocol( -# protocol=TestModbusProtocol.CLIENT_PROTOCOL) -# eq_(client._name, 'modbus') -# del client - -# except Exception as error: -# print 'ERROR test_init_client: ', error -# assert False - - -# def test_init_server(self): - -# try: -# server = ModbusProtocol( -# protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) -# eq_(server._name, 'modbus') -# server._stop_server(server._server_subprocess) -# del server - -# except Exception as error: -# print 'ERROR test_init_server: ', error -# assert False - - -# def test_send(self): - -# client = ModbusProtocol( -# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - -# ADDRESS = 'localhost:502' -# TAGS = (20, 20, 20, 20) -# OFFSET = 10 - -# try: -# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) -# time.sleep(1.0) - -# print('TEST: Write to holding registers') -# for offset in range(0, OFFSET): -# what = ('HR', offset) -# client._send(what, offset, ADDRESS) -# print('') - -# coil = True -# print('TEST: Write to coils') -# for offset in range(0, OFFSET): -# what = ('CO', offset) -# client._send(what, coil, ADDRESS) -# coil = not coil -# print('') - -# ModbusProtocol._stop_server(server) - -# except Exception as error: -# ModbusProtocol._stop_server(server) -# print 'ERROR test_send: ', error -# assert False - -# def test_receive(self): - -# client = ModbusProtocol( -# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - -# ADDRESS = 'localhost:502' -# TAGS = (20, 20, 20, 20) -# OFFSET = 10 - -# try: -# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) -# time.sleep(1.0) - -# print('TEST: Read holding registers') -# for offset in range(0, OFFSET): -# what = ('HR', offset) -# eq_(client._receive(what, ADDRESS), 0) -# print('') - -# print('TEST: Read input registers') -# for offset in range(0, OFFSET): -# what = ('IR', offset) -# eq_(client._receive(what, ADDRESS), 0) -# print('') - -# print('TEST: Read discrete inputs') -# for offset in range(0, OFFSET): -# what = ('DI', offset) -# eq_(client._receive(what, ADDRESS), False) -# print('') - -# print('TEST: Read coils inputs') -# for offset in range(0, OFFSET): -# what = ('CO', offset) -# eq_(client._receive(what, ADDRESS), False) -# print('') - -# ModbusProtocol._stop_server(server) - -# except Exception as error: -# ModbusProtocol._stop_server(server) -# print 'ERROR test_receive: ', error -# assert False - -# @SkipTest -# def test_client_server(self): - -# ADDRESS = 'localhost:502' - -# try: -# # NOTE: same instance used as server and client -# modbus = ModbusProtocol( -# protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) -# time.sleep(1.0) - -# print('TEST: Write and read coils') -# what = ('CO', 0) -# value = True -# modbus._send(what, value, ADDRESS) -# what = ('CO', 0) -# eq_(modbus._receive(what, ADDRESS), True) - -# what = ('CO', 1) -# value = False -# modbus._send(what, value, ADDRESS) -# what = ('CO', 1) -# eq_(modbus._receive(what, ADDRESS), False) -# print('') - -# print('TEST: Write and read holding registers') -# for hr in range(10): -# what = ('HR', hr) -# modbus._send(what, hr, ADDRESS) -# what = ('HR', hr) -# eq_(modbus._receive(what, ADDRESS), hr) -# print('') - -# print('TEST: Read discrete inputs (init to False)') -# what = ('DI', 0) -# eq_(modbus._receive(what, ADDRESS), False) -# print('') - -# print('TEST: Read input registers (init to 0)') -# for ir in range(10): -# what = ('IR', ir) -# eq_(modbus._receive(what, ADDRESS), 0) -# print('') - -# ModbusProtocol._stop_server(modbus._server_subprocess) - -# except Exception as error: -# ModbusProtocol._stop_server(modbus._server_subprocess) -# print 'ERROR test_client_server: ', error -# assert False - -# def test_receive_count(self): - -# client = ModbusProtocol( -# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - -# ADDRESS = 'localhost:502' -# TAGS = (20, 20, 20, 20) - -# try: -# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) -# time.sleep(1.0) - -# print('TEST: Read holding registers, count=3') -# what = ('HR', 0) -# eq_(client._receive(what, ADDRESS, count=3), [0, 0, 0]) -# print('') - -# print('TEST: Read input registers, count=1') -# what = ('IR', 0) -# eq_(client._receive(what, ADDRESS, count=1), 0) -# print('') - -# print('TEST: Read discrete inputs, count=2') -# what = ('DI', 0) -# eq_(client._receive(what, ADDRESS, count=2), [False] * 2) -# print('') - -# print('TEST: Read coils, count=9') -# what = ('CO', 0) -# eq_(client._receive(what, ADDRESS, count=9), [False] * 9) -# print('') - -# ModbusProtocol._stop_server(server) - -# except Exception as error: -# ModbusProtocol._stop_server(server) -# print 'ERROR test_receive_count: ', error -# assert False - -# def test_client_server_count(self): - -# client = ModbusProtocol( -# protocol=TestModbusProtocol.CLIENT_PROTOCOL) - -# ADDRESS = 'localhost:502' -# TAGS = (50, 50, 50, 50) - -# try: -# server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) -# time.sleep(1.0) - -# print('TEST: Write and Read holding registers, offset=4, count=3') -# what = ('HR', 4) -# hrs = [1, 2, 3] -# client._send(what, hrs, ADDRESS, count=3) -# eq_(client._receive(what, ADDRESS, count=3), hrs) -# print('') - -# print('TEST: Write and Read holding registers, offset=4, count=3') -# what = ('CO', 7) -# cos = [True, False, False, True, False] -# client._send(what, cos, ADDRESS, count=5) -# eq_(client._receive(what, ADDRESS, count=5), cos) -# print('') - -# ModbusProtocol._stop_server(server) - -# except Exception as error: -# ModbusProtocol._stop_server(server) -# print 'ERROR test_client_server_count: ', error -# assert False +class TestModbusProtocol(): + + # NOTE: current API specifies only the number of tags + TAGS = (200, 200, 200, 200) + # TAGS = ( + # ('CO1', 1, 'CO'), + # ('CO1', 2, 'CO'), + # ('DI1', 1, 'DI'), + # ('DI1', 2, 'DI'), + # ('HR1', 1, 'HR'), + # ('HR2', 2, 'HR'), + # ('IR1', 1, 'IR'), + # ('IR2', 4, 'IR')) + SERVER = { + 'address': 'localhost:502', + 'tags': TAGS + } + CLIENT_SERVER_PROTOCOL = { + 'name': 'modbus', + 'mode': 1, + 'server': SERVER, + } + CLIENT_PROTOCOL = { + 'name': 'modbus', + 'mode': 0, + 'server': '', + } + if sys.platform.startswith('linux'): + SHELL = '/bin/bash -c ' + CLIENT_LOG = '--log logs/protocols_tests_modbus_client ' + else: + raise OSError + + from minicps import __file__ as minicps_path + minicps_path = minicps_path[:-12] + SERVER_CMD_PATH = sys.executable + ' ' + minicps_path + \ + 'pymodbus/servers.py ' # NOTE: ending whitespace + + def test_server_start_stop(self): + + try: + server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, + 'localhost:502', self.TAGS) + ModbusProtocol._stop_server(server) + + except Exception as error: + print 'ERROR test_server_start_stop: ', error + assert False + + + def test_init_client(self): + + try: + client = ModbusProtocol( + protocol=TestModbusProtocol.CLIENT_PROTOCOL) + eq_(client._name, 'modbus') + del client + + except Exception as error: + print 'ERROR test_init_client: ', error + assert False + + + def test_init_server(self): + + try: + server = ModbusProtocol( + protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) + eq_(server._name, 'modbus') + server._stop_server(server._server_subprocess) + del server + + except Exception as error: + print 'ERROR test_init_server: ', error + assert False + + + def test_send(self): + + client = ModbusProtocol( + protocol=TestModbusProtocol.CLIENT_PROTOCOL) + + ADDRESS = 'localhost:502' + TAGS = (20, 20, 20, 20) + OFFSET = 10 + + try: + server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) + time.sleep(1.0) + + print('TEST: Write to holding registers') + for offset in range(0, OFFSET): + what = ('HR', offset) + client._send(what, offset, ADDRESS) + print('') + + coil = True + print('TEST: Write to coils') + for offset in range(0, OFFSET): + what = ('CO', offset) + client._send(what, coil, ADDRESS) + coil = not coil + print('') + + ModbusProtocol._stop_server(server) + + except Exception as error: + ModbusProtocol._stop_server(server) + print 'ERROR test_send: ', error + assert False + + def test_receive(self): + + client = ModbusProtocol( + protocol=TestModbusProtocol.CLIENT_PROTOCOL) + + ADDRESS = 'localhost:502' + TAGS = (20, 20, 20, 20) + OFFSET = 10 + + try: + server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) + time.sleep(1.0) + + print('TEST: Read holding registers') + for offset in range(0, OFFSET): + what = ('HR', offset) + eq_(client._receive(what, ADDRESS), 0) + print('') + + print('TEST: Read input registers') + for offset in range(0, OFFSET): + what = ('IR', offset) + eq_(client._receive(what, ADDRESS), 0) + print('') + + print('TEST: Read discrete inputs') + for offset in range(0, OFFSET): + what = ('DI', offset) + eq_(client._receive(what, ADDRESS), False) + print('') + + print('TEST: Read coils inputs') + for offset in range(0, OFFSET): + what = ('CO', offset) + eq_(client._receive(what, ADDRESS), False) + print('') + + ModbusProtocol._stop_server(server) + + except Exception as error: + ModbusProtocol._stop_server(server) + print 'ERROR test_receive: ', error + assert False + + @SkipTest + def test_client_server(self): + + ADDRESS = 'localhost:502' + + try: + # NOTE: same instance used as server and client + modbus = ModbusProtocol( + protocol=TestModbusProtocol.CLIENT_SERVER_PROTOCOL) + time.sleep(1.0) + + print('TEST: Write and read coils') + what = ('CO', 0) + value = True + modbus._send(what, value, ADDRESS) + what = ('CO', 0) + eq_(modbus._receive(what, ADDRESS), True) + + what = ('CO', 1) + value = False + modbus._send(what, value, ADDRESS) + what = ('CO', 1) + eq_(modbus._receive(what, ADDRESS), False) + print('') + + print('TEST: Write and read holding registers') + for hr in range(10): + what = ('HR', hr) + modbus._send(what, hr, ADDRESS) + what = ('HR', hr) + eq_(modbus._receive(what, ADDRESS), hr) + print('') + + print('TEST: Read discrete inputs (init to False)') + what = ('DI', 0) + eq_(modbus._receive(what, ADDRESS), False) + print('') + + print('TEST: Read input registers (init to 0)') + for ir in range(10): + what = ('IR', ir) + eq_(modbus._receive(what, ADDRESS), 0) + print('') + + ModbusProtocol._stop_server(modbus._server_subprocess) + + except Exception as error: + ModbusProtocol._stop_server(modbus._server_subprocess) + print 'ERROR test_client_server: ', error + assert False + + def test_receive_count(self): + + client = ModbusProtocol( + protocol=TestModbusProtocol.CLIENT_PROTOCOL) + + ADDRESS = 'localhost:502' + TAGS = (20, 20, 20, 20) + + try: + server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) + time.sleep(1.0) + + print('TEST: Read holding registers, count=3') + what = ('HR', 0) + eq_(client._receive(what, ADDRESS, count=3), [0, 0, 0]) + print('') + + print('TEST: Read input registers, count=1') + what = ('IR', 0) + eq_(client._receive(what, ADDRESS, count=1), 0) + print('') + + print('TEST: Read discrete inputs, count=2') + what = ('DI', 0) + eq_(client._receive(what, ADDRESS, count=2), [False] * 2) + print('') + + print('TEST: Read coils, count=9') + what = ('CO', 0) + eq_(client._receive(what, ADDRESS, count=9), [False] * 9) + print('') + + ModbusProtocol._stop_server(server) + + except Exception as error: + ModbusProtocol._stop_server(server) + print 'ERROR test_receive_count: ', error + assert False + + def test_client_server_count(self): + + client = ModbusProtocol( + protocol=TestModbusProtocol.CLIENT_PROTOCOL) + + ADDRESS = 'localhost:502' + TAGS = (50, 50, 50, 50) + + try: + server = ModbusProtocol._start_server(self.SERVER_CMD_PATH, ADDRESS, TAGS) + time.sleep(1.0) + + print('TEST: Write and Read holding registers, offset=4, count=3') + what = ('HR', 4) + hrs = [1, 2, 3] + client._send(what, hrs, ADDRESS, count=3) + eq_(client._receive(what, ADDRESS, count=3), hrs) + print('') + + print('TEST: Write and Read holding registers, offset=4, count=3') + what = ('CO', 7) + cos = [True, False, False, True, False] + client._send(what, cos, ADDRESS, count=5) + eq_(client._receive(what, ADDRESS, count=5), cos) + print('') + + ModbusProtocol._stop_server(server) + + except Exception as error: + ModbusProtocol._stop_server(server) + print 'ERROR test_client_server_count: ', error + assert False # # }}} From f854e2ff164b3e29b863feec5e0b2cd88137acd5 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Mon, 10 Apr 2017 11:29:55 +0800 Subject: [PATCH 09/31] error handling by import class from pycomm incase bug is not fixed from pycomm --- minicps/pyenip/single_read.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index 526a002..848a7c9 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -8,6 +8,7 @@ import argparse # TODO: check if it is too slow at runtime from pycomm.ab_comm.clx import Driver as ClxDriver +from pycomm.cip.cip_base import DataError def read_tag(address, tag_name): plc = ClxDriver() @@ -18,6 +19,8 @@ def read_tag(address, tag_name): return (tagg) else: return ("u", ) + except DataError as e: + return False, "Check Encapsulation and Message Router Error" except Exception as e: return ("e",) From 6d818277df100eeaf0667c6c5dce9eba2b3b40f7 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Mon, 10 Apr 2017 16:08:37 +0800 Subject: [PATCH 10/31] undid the last commit because pycomm is handling the specified error properly --- minicps/pyenip/single_read.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index 848a7c9..526a002 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -8,7 +8,6 @@ import argparse # TODO: check if it is too slow at runtime from pycomm.ab_comm.clx import Driver as ClxDriver -from pycomm.cip.cip_base import DataError def read_tag(address, tag_name): plc = ClxDriver() @@ -19,8 +18,6 @@ def read_tag(address, tag_name): return (tagg) else: return ("u", ) - except DataError as e: - return False, "Check Encapsulation and Message Router Error" except Exception as e: return ("e",) From df6ab57ae50fcebe239ca005d4894a8a0fb1d941 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Tue, 11 Apr 2017 11:42:45 +0800 Subject: [PATCH 11/31] commented debug tags --- minicps/protocols.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index c3fbff4..a864bc4 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -179,7 +179,7 @@ def __init__(self, protocol): else: raise OSError - print 'DEBUG EnipProtocol server addr: ', self._server['address'] + #print 'DEBUG EnipProtocol server addr: ', self._server['address'] if self._server['address'].find(':') == -1: print 'DEBUG: concatenating server address with default port.' self._server['address'] += EnipProtocol._TCP_PORT @@ -204,7 +204,7 @@ def _nested_tuples_to_enip_tags(cls, tags): """ Tuple to input format for server script init :tags: ((SENSOR1, BOOL), (ACTUATOR1, 1, SINT), (TEMP2, REAL)) :return: a string of the tuples (name and type separated by serializer) separated by white space - E.g. 'sensor1_BOOL actuator1:1_SINT temp2_REAL' + E.g. 'sensor1@BOOL actuator1:1@SINT temp2@REAL' """ tag_list = [cls._tuple_to_enip_tags(tag) for tag in tags] return '--tags ' + ' '.join(tag_list) @@ -248,7 +248,7 @@ def _start_server_cmd(cls, address='localhost:44818', ADDRESS + TAGS ) - print 'DEBUG enip _start_server cmd: ', cmd + # print 'DEBUG enip _start_server cmd: ', cmd return cmd @@ -307,7 +307,7 @@ def _send(self, what, value, address='localhost', **kwargs): TAG + VAL ) - print 'DEBUG enip _start_server cmd: ', cmd + # print 'DEBUG enip _start_server cmd: ', cmd try: client = subprocess.Popen(cmd, shell=False, @@ -315,7 +315,7 @@ def _send(self, what, value, address='localhost', **kwargs): # client.communicate is blocking raw_out = client.communicate() - print 'DEBUG enip _receive raw_out: ', raw_out + # print 'DEBUG enip _receive raw_out: ', raw_out #value is stored as first tuple element return raw_out[0] @@ -348,7 +348,7 @@ def _receive(self, what, address='localhost'): ADDRESS + TAG ) - print 'DEBUG enip _start_server cmd: ', cmd + # print 'DEBUG enip _start_server cmd: ', cmd try: client = subprocess.Popen(cmd, shell=False, @@ -356,7 +356,7 @@ def _receive(self, what, address='localhost'): # client.communicate is blocking raw_out = client.communicate() - print 'DEBUG enip _receive raw_out: ', raw_out + # print 'DEBUG enip _receive raw_out: ', raw_out #value is stored as first tuple element return raw_out[0] From d2705da8f94487d52ef22e470ce3a60bf99a2946 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Tue, 18 Apr 2017 11:56:20 +0800 Subject: [PATCH 12/31] single_write handles invalid tag format --- minicps/pyenip/single_write.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/minicps/pyenip/single_write.py b/minicps/pyenip/single_write.py index 6804407..877e22c 100755 --- a/minicps/pyenip/single_write.py +++ b/minicps/pyenip/single_write.py @@ -7,7 +7,8 @@ """ import argparse # TODO: check if it is too slow at runtime -from pycomm.ab_comm.clx import Driver as ClxDriver +import sys +from pycomm.clx import Driver as ClxDriver def convert_value_to_type(tag_type, val): if tag_type == "INT" or tag_type == "DINT" or tag_type == "SINT": value = int(val) @@ -36,7 +37,7 @@ def write_tag(tag_name, value, tag_type): help='request ip') parser.add_argument('-t', '--tag', type=str, dest='tag', required=True, - help='request tag with type') + help='request tag with type. format: NAME[:ID]@TYPE') parser.add_argument('-v', '--val', type=str, dest='val', required=True, help='value to be written') @@ -44,8 +45,18 @@ def write_tag(tag_name, value, tag_type): args = parser.parse_args() # split tags to retrieve type - tag_name, tag_type = args.tag.split("@") + try: + tag_name, tag_type = args.tag.split("@") + + except ValueError as e: + print("single_write.py: error: invalid tag format.") + print("usage: single_write.py -h for help") + sys.exit(0) + if not tag_type: + print("single_write.py: error: tag type is invalid.") + print("usage: single_write.py -h for help") + sys.exit(0) # retrieve the ip and ignore the port address = args.ip.split(":")[0] From 0095a254197feb6fc0cfeeb919cbf2f01a5b6e00 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Tue, 18 Apr 2017 11:56:58 +0800 Subject: [PATCH 13/31] correct pycomm import --- minicps/pyenip/single_write.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minicps/pyenip/single_write.py b/minicps/pyenip/single_write.py index 877e22c..68d019e 100755 --- a/minicps/pyenip/single_write.py +++ b/minicps/pyenip/single_write.py @@ -8,7 +8,7 @@ import argparse # TODO: check if it is too slow at runtime import sys -from pycomm.clx import Driver as ClxDriver +from pycomm.ab_comm.clx import Driver as ClxDriver def convert_value_to_type(tag_type, val): if tag_type == "INT" or tag_type == "DINT" or tag_type == "SINT": value = int(val) From ed3f0099e74eee5fc924ca6f3f3f2abbbeabf96c Mon Sep 17 00:00:00 2001 From: ahnaf Date: Tue, 18 Apr 2017 12:02:11 +0800 Subject: [PATCH 14/31] handles changes in single non-existent read_tag --- minicps/pyenip/single_read.py | 1 + 1 file changed, 1 insertion(+) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index 526a002..853a021 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -15,6 +15,7 @@ def read_tag(address, tag_name): if plc.open(address): tagg = plc.read_tag(tag_name) plc.close() + if not tagg: return (False, ) return (tagg) else: return ("u", ) From 6b0edad653baf101a597fb736d9aa499b5cf194e Mon Sep 17 00:00:00 2001 From: ahnafsidd Date: Thu, 27 Apr 2017 11:04:15 +0800 Subject: [PATCH 15/31] added test cases for STRING type for read and write --- tests/protocols_tests.py | 52 +++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index 16b2abb..339c4c9 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -33,7 +33,10 @@ class TestEnipProtocol(): TAGS = ( ('SENSOR1', 1, 'INT'), ('SENSOR1', 2, 'INT'), - ('ACTUATOR1', 'INT')) + ('ACTUATOR1', 'INT'), + ('FLAG101', 'STRING'), + ('FLAG201', 2, 'STRING')) + SERVER = { 'address': 'localhost:44818', 'tags': TAGS @@ -93,7 +96,7 @@ def test_init_server(self): def test_server_multikey(self): ADDRESS = 'localhost:44818' # TEST port - TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT')) + TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT'), ('FLAG2', 2, 'STRING')) try: server = EnipProtocol._start_server(ADDRESS, TAGS) EnipProtocol._stop_server(server) @@ -107,7 +110,7 @@ def test_send_multikey(self): protocol=TestEnipProtocol.CLIENT_PROTOCOL) ADDRESS = 'localhost:44818' # TEST port - TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT')) + TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 1, 'INT'), ('FLAG101', 2, 'STRING')) try: server = EnipProtocol._start_server(ADDRESS, TAGS) @@ -117,12 +120,17 @@ def test_send_multikey(self): for value in range(5): enip._send(what, value, ADDRESS) - # write a single key - what = ('ACTUATOR1', 'INT') + # write a multi key + what = ('ACTUATOR1', 1, 'INT') for value in range(5): enip._send(what, 1, ADDRESS) - # write a single key + # write a multi key + what = ('FLAG101', 2,'STRING') + for value in range(5): + enip._send(what, chr(127-value)*6, ADDRESS) + + # write a multi key what = ('HMI_TEST101', 'REAL') for value in range(5): enip._send(what, 1, ADDRESS) @@ -139,7 +147,7 @@ def test_receive_multikey(self): protocol=TestEnipProtocol.CLIENT_PROTOCOL) ADDRESS = 'localhost:44818' # TEST port - TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT')) + TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 1, 'INT'), ('FLAG101', 2, 'STRING')) try: server = EnipProtocol._start_server(ADDRESS, TAGS) @@ -150,16 +158,20 @@ def test_receive_multikey(self): address = 'localhost:44818' enip._receive(what, ADDRESS) - # read a single key - what = ('ACTUATOR1',) + # read a multi key + what = ('ACTUATOR1',1) address = 'localhost:44818' enip._receive(what, ADDRESS) - # Read a single key - present tag + # Read a single key - uninitialized tag - error shouldn't occur what = ('HMI_TEST101',) address = 'localhost:44818' enip._receive(what, ADDRESS) + # Read a multi key + what = ('FLAG101', 2) + enip._receive(what,ADDRESS) + EnipProtocol._stop_server(server) except Exception as error: @@ -191,6 +203,14 @@ def test_client_server(self): what = ('HMI_TEST101',) enip._receive(what, ADDRESS) + # read a single key + what = ('FLAG101',) + enip._receive(what, ADDRESS) + + # read a single key + what = ('FLAG201', 2) + enip._receive(what, ADDRESS) + # write a multikey what = ('SENSOR1', 1, 'INT') # added type here for value in range(5): @@ -201,11 +221,21 @@ def test_client_server(self): for value in range(5): enip._send(what, value, ADDRESS) - # write a single key - present + # write a single key - uninitialized tag - error shouldn't occur what = ('HMI_TEST101', 'REAL') # added type here for value in range(5): enip._send(what, value, ADDRESS) + # write a single key + what = ('FLAG101', 'STRING') # added type here + for value in range(5): + enip._send(what, value, ADDRESS) + + # write a multi key + what = ('FLAG201', 2, 'STRING') # added type here + for value in range(5): + enip._send(what, chr(127-value)*8, ADDRESS) + EnipProtocol._stop_server(enip._server_subprocess) except Exception as error: From e4d91da542f13bd713f1804f644621513edefa92 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 28 Apr 2017 14:58:59 +0800 Subject: [PATCH 16/31] configured write script to adhere to minicps send api format --- minicps/protocols.py | 39 +++++++++++++++++------------ minicps/pyenip/single_read.py | 4 +-- minicps/pyenip/single_write.py | 45 ++++++++++++++++------------------ 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index a864bc4..661ae6c 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -179,7 +179,7 @@ def __init__(self, protocol): else: raise OSError - #print 'DEBUG EnipProtocol server addr: ', self._server['address'] + # print 'DEBUG EnipProtocol server addr: ', self._server['address'] if self._server['address'].find(':') == -1: print 'DEBUG: concatenating server address with default port.' self._server['address'] += EnipProtocol._TCP_PORT @@ -194,11 +194,6 @@ def __init__(self, protocol): # TODO: udp enip server elif self._mode == 2: pass - @classmethod - def _tuple_to_enip_tags(cls, tag): - tag = [str(x) for x in tag] - return "{0}@{1}".format(':'.join(tag[:-1]), tag[-1]) - @classmethod def _nested_tuples_to_enip_tags(cls, tags): """ Tuple to input format for server script init @@ -206,7 +201,10 @@ def _nested_tuples_to_enip_tags(cls, tags): :return: a string of the tuples (name and type separated by serializer) separated by white space E.g. 'sensor1@BOOL actuator1:1@SINT temp2@REAL' """ - tag_list = [cls._tuple_to_enip_tags(tag) for tag in tags] + tag_list = [] + for tag in tags: + tag = [str(x) for x in tag] + tag_list.append("{0}@{1}".format(':'.join(tag[:-1]), tag[-1])) return '--tags ' + ' '.join(tag_list) @classmethod @@ -288,24 +286,35 @@ def _send(self, what, value, address='localhost', **kwargs): It is a blocking operation the parent process will wait till the child cpppo process returns. - :what: tuple of (tag name, datatype) + :what: tag :value: sent :address: ip """ - tag = self._tuple_to_enip_tags(what) + def infer_tag_type(val): + if type(val) is float: _typ = "REAL" + elif type(val) is int: _typ = "INT" + elif type(val) is str: _typ = "STRING" + elif type(val) is bool: _typ = "BOOL" + else: _typ = "unsupported" + return _typ + + tag = ':'.join([str(x) for x in what]) + typ = infer_tag_type(value) ENV = "python " #sys.executable CMD = "{0}pyenip/single_write.py ".format(self._minicps_path) ADDRESS = "-i {0} ".format(address) TAG = "-t {0} ".format(tag) - VAL = "-v {0}".format(value) + VAL = "-v '{}' ".format(str(value)) + TYP = "--type {}".format(typ) cmd = shlex.split( ENV + CMD + ADDRESS + TAG + - VAL + VAL + + TYP ) # print 'DEBUG enip _start_server cmd: ', cmd @@ -417,9 +426,9 @@ def __init__(self, protocol): else: raise OSError - print 'DEBUG ModbusProtocol server addr: ', self._server['address'] + # print 'DEBUG ModbusProtocol server addr: ', self._server['address'] if self._server['address'].find(':') == -1: - print 'DEBUG: concatenating server address with default port.' + # print 'DEBUG: concatenating server address with default port.' self._server['address'] += ModbusProtocol._TCP_PORT elif not self._server['address'].endswith(ModbusProtocol._TCP_PORT): @@ -428,7 +437,7 @@ def __init__(self, protocol): server_cmd_path = sys.executable + ' ' + self._minicps_path + \ 'pymodbus/servers.py ' # NOTE: ending whitespace - print 'DEBUG: generating server_cmd_path: {}'.format(server_cmd_path) + # print 'DEBUG: generating server_cmd_path: {}'.format(server_cmd_path) self._server_subprocess = ModbusProtocol._start_server( address=self._server['address'], @@ -510,7 +519,7 @@ def _start_server_cmd(cls, cmd_path, address='localhost:502', MODE + DI + CO + IR + HR ) - print 'DEBUG modbus _start_server cmd: ', cmd + # print 'DEBUG modbus _start_server cmd: ', cmd return cmd diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index 853a021..5623e79 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -44,9 +44,7 @@ def read_tag(address, tag_name): val = res[0] - if val == "e": - print("Unable to open connection at : {}".format(address)) - elif val == "u": + if val == "u": print("Unknown Error! Please check server log.") elif val == False: print("Read unsuccesful. Please check server log.") diff --git a/minicps/pyenip/single_write.py b/minicps/pyenip/single_write.py index 68d019e..302434f 100755 --- a/minicps/pyenip/single_write.py +++ b/minicps/pyenip/single_write.py @@ -8,12 +8,14 @@ import argparse # TODO: check if it is too slow at runtime import sys -from pycomm.ab_comm.clx import Driver as ClxDriver +from pycomm.clx import Driver as ClxDriver -def convert_value_to_type(tag_type, val): - if tag_type == "INT" or tag_type == "DINT" or tag_type == "SINT": value = int(val) +def convert_value_to_proper_type(tag_type, val): + if tag_type == "INT": value = int(val) elif tag_type == "REAL": value = float(val) - elif tag_type == "BOOL": value = bool(val) + elif tag_type == "BOOL": + if val == "False" or val == 0: value = False + else: value = True else: value = str(val) return value @@ -27,7 +29,7 @@ def write_tag(tag_name, value, tag_type): else: return "u" except Exception as e: - return "e" + raise e if __name__ == "__main__": @@ -37,36 +39,31 @@ def write_tag(tag_name, value, tag_type): help='request ip') parser.add_argument('-t', '--tag', type=str, dest='tag', required=True, - help='request tag with type. format: NAME[:ID]@TYPE') + help='request tag with type. format: NAME[:ID][:ID]...') - parser.add_argument('-v', '--val', type=str, dest='val', required=True, - help='value to be written') + parser.add_argument('-v', '--val', dest='val', required=True, + help='value to be written.') - args = parser.parse_args() + parser.add_argument('--type', dest='typ', required=True, + help='[INT][STRING][REAL]') - # split tags to retrieve type - try: - tag_name, tag_type = args.tag.split("@") + args = parser.parse_args() - except ValueError as e: - print("single_write.py: error: invalid tag format.") - print("usage: single_write.py -h for help") - sys.exit(0) + tag_name = args.tag + tag_type = args.typ + value = convert_value_to_proper_type(tag_type, args.val) - if not tag_type: - print("single_write.py: error: tag type is invalid.") - print("usage: single_write.py -h for help") - sys.exit(0) # retrieve the ip and ignore the port address = args.ip.split(":")[0] - value = convert_value_to_type(tag_type, args.val) + if tag_type not in ["INT", "STRING", "REAL"]: + print("single_write.py: error: tag type is invalid.") + print("usage: single_write.py -h for help") + raise ValueError("single_write.py: error: tag type is invalid. Only INT, STRING, and FLOAT is supported.") res = write_tag(tag_name, value, tag_type) - if res == "e": - print("Unable to open connection at : {}".format(address)) - elif res: + if res: print("Successfully written value: {0} for tag: {1}".format(value, tag_name)) else: print("Write unsuccesful. Please check server log.") From 429d5ce5b79310d95b0ffd287ed0cd14fdc36264 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 28 Apr 2017 15:00:02 +0800 Subject: [PATCH 17/31] raise error if unable to connect --- minicps/pyenip/single_read.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index 5623e79..43c463a 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -20,7 +20,7 @@ def read_tag(address, tag_name): else: return ("u", ) except Exception as e: - return ("e",) + raise e if __name__ == "__main__": From 501fb9842d1cdf863bd8301e810313eea64fd551 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 28 Apr 2017 15:00:48 +0800 Subject: [PATCH 18/31] raise error if unable to connect --- minicps/pyenip/single_read.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index 43c463a..2c60ecd 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -20,7 +20,7 @@ def read_tag(address, tag_name): else: return ("u", ) except Exception as e: - raise e + raise ValueError(e) if __name__ == "__main__": From 5f56b9c7b0e4c53e46d53b21fbaadb473dae83d0 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 28 Apr 2017 15:01:25 +0800 Subject: [PATCH 19/31] reverted test cases to follow minicps api --- tests/protocols_tests.py | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index 339c4c9..8c4571a 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -116,22 +116,22 @@ def test_send_multikey(self): server = EnipProtocol._start_server(ADDRESS, TAGS) time.sleep(1) # wait for the server to actually start so client can connect # write a multikey - what = ('SENSOR1', 1, 'INT') # added type here + what = ('SENSOR1', 1) for value in range(5): enip._send(what, value, ADDRESS) # write a multi key - what = ('ACTUATOR1', 1, 'INT') + what = ('ACTUATOR1', 1) for value in range(5): enip._send(what, 1, ADDRESS) # write a multi key - what = ('FLAG101', 2,'STRING') + what = ('FLAG101', 2) for value in range(5): enip._send(what, chr(127-value)*6, ADDRESS) # write a multi key - what = ('HMI_TEST101', 'REAL') + what = ('HMI_TEST101',) for value in range(5): enip._send(what, 1, ADDRESS) @@ -163,7 +163,7 @@ def test_receive_multikey(self): address = 'localhost:44818' enip._receive(what, ADDRESS) - # Read a single key - uninitialized tag - error shouldn't occur + # Read a single key - uninitialized tag what = ('HMI_TEST101',) address = 'localhost:44818' enip._receive(what, ADDRESS) @@ -212,29 +212,29 @@ def test_client_server(self): enip._receive(what, ADDRESS) # write a multikey - what = ('SENSOR1', 1, 'INT') # added type here - for value in range(5): - enip._send(what, value, ADDRESS) - - # write a single key - what = ('ACTUATOR1', 'INT') # added type here - for value in range(5): - enip._send(what, value, ADDRESS) - - # write a single key - uninitialized tag - error shouldn't occur - what = ('HMI_TEST101', 'REAL') # added type here - for value in range(5): - enip._send(what, value, ADDRESS) - - # write a single key - what = ('FLAG101', 'STRING') # added type here + what = ('SENSOR1', 1) for value in range(5): enip._send(what, value, ADDRESS) - # write a multi key - what = ('FLAG201', 2, 'STRING') # added type here - for value in range(5): - enip._send(what, chr(127-value)*8, ADDRESS) + # # write a single key + # what = ('ACTUATOR1',) + # for value in range(5): + # enip._send(what, value, ADDRESS) + + # # write a single key - uninitialized tag - error shouldn't occur + # what = ('HMI_TEST101') + # for value in range(5): + # enip._send(what, value, ADDRESS) + + # # write a single key + # what = ('FLAG101') + # for value in range(5): + # enip._send(what, str(127-value)*8, ADDRESS) + + # # write a multi key + # what = ('FLAG201', 2) + # for value in range(5): + # enip._send(what, chr(127-value)*8, ADDRESS) EnipProtocol._stop_server(enip._server_subprocess) From 5d94ea8123f453e00ac0d8b141fac9c4da9bbfeb Mon Sep 17 00:00:00 2001 From: ahnaf Date: Wed, 3 May 2017 16:27:00 +0800 Subject: [PATCH 20/31] bugfix: fixed pycomm import --- minicps/pyenip/single_write.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minicps/pyenip/single_write.py b/minicps/pyenip/single_write.py index 302434f..2dd4154 100755 --- a/minicps/pyenip/single_write.py +++ b/minicps/pyenip/single_write.py @@ -8,7 +8,7 @@ import argparse # TODO: check if it is too slow at runtime import sys -from pycomm.clx import Driver as ClxDriver +from pycomm.ab_comm.clx import Driver as ClxDriver def convert_value_to_proper_type(tag_type, val): if tag_type == "INT": value = int(val) From 0106f735afc17ec344248be66f2898570a8929fb Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 5 May 2017 09:40:19 +0800 Subject: [PATCH 21/31] supress debug messages --- minicps/protocols.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index 661ae6c..c12e2b5 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -181,7 +181,7 @@ def __init__(self, protocol): # print 'DEBUG EnipProtocol server addr: ', self._server['address'] if self._server['address'].find(':') == -1: - print 'DEBUG: concatenating server address with default port.' + # print 'DEBUG: concatenating server address with default port.' self._server['address'] += EnipProtocol._TCP_PORT elif not self._server['address'].endswith(EnipProtocol._TCP_PORT): @@ -323,11 +323,7 @@ def infer_tag_type(val): stdout=subprocess.PIPE) # client.communicate is blocking - raw_out = client.communicate() - # print 'DEBUG enip _receive raw_out: ', raw_out - - #value is stored as first tuple element - return raw_out[0] + client.wait() except Exception as error: print 'ERROR enip _send: ', error @@ -367,7 +363,7 @@ def _receive(self, what, address='localhost'): raw_out = client.communicate() # print 'DEBUG enip _receive raw_out: ', raw_out - #value is stored as first tuple element + # value is stored as first tuple element return raw_out[0] except Exception as error: @@ -426,7 +422,7 @@ def __init__(self, protocol): else: raise OSError - # print 'DEBUG ModbusProtocol server addr: ', self._server['address'] + print 'DEBUG ModbusProtocol server addr: ', self._server['address'] if self._server['address'].find(':') == -1: # print 'DEBUG: concatenating server address with default port.' self._server['address'] += ModbusProtocol._TCP_PORT @@ -437,7 +433,7 @@ def __init__(self, protocol): server_cmd_path = sys.executable + ' ' + self._minicps_path + \ 'pymodbus/servers.py ' # NOTE: ending whitespace - # print 'DEBUG: generating server_cmd_path: {}'.format(server_cmd_path) + print 'DEBUG: generating server_cmd_path: {}'.format(server_cmd_path) self._server_subprocess = ModbusProtocol._start_server( address=self._server['address'], From 00ac82529e5902294296d642b82f3c28667079d7 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 5 May 2017 09:40:50 +0800 Subject: [PATCH 22/31] updated to return value only --- minicps/pyenip/single_read.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index 2c60ecd..eb258b7 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -15,7 +15,6 @@ def read_tag(address, tag_name): if plc.open(address): tagg = plc.read_tag(tag_name) plc.close() - if not tagg: return (False, ) return (tagg) else: return ("u", ) @@ -44,10 +43,8 @@ def read_tag(address, tag_name): val = res[0] - if val == "u": - print("Unknown Error! Please check server log.") - elif val == False: - print("Read unsuccesful. Please check server log.") + if val == "u" or res[1] == 'Check Encapsulation and Message Router Error': + print("check server log.") else: - print("Success! Value: {0} for Tag: {1}. Type: {2}".format(val, tag_name, res[1])) + print("{}".format(val)) From cb469c336e800e6e09847a91ac4146cedbbe4637 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 5 May 2017 09:41:17 +0800 Subject: [PATCH 23/31] updated test cases to check for values --- tests/protocols_tests.py | 56 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index 8c4571a..7492f52 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -156,21 +156,21 @@ def test_receive_multikey(self): # read a multikey what = ('SENSOR1', 1) address = 'localhost:44818' - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS), "0\n") # read a multi key what = ('ACTUATOR1',1) address = 'localhost:44818' - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS), "0\n") # Read a single key - uninitialized tag what = ('HMI_TEST101',) address = 'localhost:44818' - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS), "check server log.\n") # Read a multi key what = ('FLAG101', 2) - enip._receive(what,ADDRESS) + eq_(enip._receive(what, ADDRESS), 'enipserver\n') EnipProtocol._stop_server(server) @@ -193,48 +193,48 @@ def test_client_server(self): # read a multikey what = ('SENSOR1', 1) - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS), '0\n') # read a single key what = ('ACTUATOR1',) - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS), '0\n') # read a single key - present tag what = ('HMI_TEST101',) - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS), "check server log.\n") # read a single key what = ('FLAG101',) - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS),'enipserver\n') # read a single key what = ('FLAG201', 2) - enip._receive(what, ADDRESS) + eq_(enip._receive(what, ADDRESS),'enipserver\n') # 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) - - # # write a single key - uninitialized tag - error shouldn't occur - # what = ('HMI_TEST101') - # for value in range(5): - # enip._send(what, value, ADDRESS) - - # # write a single key - # what = ('FLAG101') - # for value in range(5): - # enip._send(what, str(127-value)*8, ADDRESS) - - # # write a multi key - # what = ('FLAG201', 2) - # for value in range(5): - # enip._send(what, chr(127-value)*8, ADDRESS) + # write a single key + what = ('ACTUATOR1',) + for value in range(5): + enip._send(what, value, ADDRESS) + + # write a single key - uninitialized tag - error shouldn't occur + what = ('HMI_TEST101') + for value in range(5): + enip._send(what, value, ADDRESS) + + # write a single key + what = ('FLAG101') + for value in range(5): + enip._send(what, str(127-value)*8, ADDRESS) + + # write a multi key + what = ('FLAG201', 2) + for value in range(5): + enip._send(what, chr(127-value)*8, ADDRESS) EnipProtocol._stop_server(enip._server_subprocess) From 575c00d2c26080905481c0576b28640943dbe160 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 5 May 2017 12:17:59 +0800 Subject: [PATCH 24/31] passing to stdout through sys calls --- minicps/pyenip/single_read.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index eb258b7..bf580ca 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -7,7 +7,8 @@ """ import argparse # TODO: check if it is too slow at runtime -from pycomm.ab_comm.clx import Driver as ClxDriver +import sys +from pycomm.clx import Driver as ClxDriver def read_tag(address, tag_name): plc = ClxDriver() @@ -44,7 +45,7 @@ def read_tag(address, tag_name): val = res[0] if val == "u" or res[1] == 'Check Encapsulation and Message Router Error': - print("check server log.") + sys.stdout.write('check server log.') else: - print("{}".format(val)) + sys.stdout.write("%s" % val) From 06304772a1b62613d2519bb0ad3df1b70235eb9e Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 5 May 2017 12:20:57 +0800 Subject: [PATCH 25/31] removed print statements as it is not necessary --- minicps/pyenip/single_write.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/minicps/pyenip/single_write.py b/minicps/pyenip/single_write.py index 2dd4154..3deff1b 100755 --- a/minicps/pyenip/single_write.py +++ b/minicps/pyenip/single_write.py @@ -29,7 +29,7 @@ def write_tag(tag_name, value, tag_type): else: return "u" except Exception as e: - raise e + raise Exception(e) if __name__ == "__main__": @@ -62,12 +62,3 @@ def write_tag(tag_name, value, tag_type): raise ValueError("single_write.py: error: tag type is invalid. Only INT, STRING, and FLOAT is supported.") res = write_tag(tag_name, value, tag_type) - - if res: - print("Successfully written value: {0} for tag: {1}".format(value, tag_name)) - else: - print("Write unsuccesful. Please check server log.") - - - - From 50567dd90997fddd6cbb54324990753f4ab9db89 Mon Sep 17 00:00:00 2001 From: ahnaf Date: Fri, 5 May 2017 12:23:58 +0800 Subject: [PATCH 26/31] bugix: fixed import from ab_comm --- minicps/pyenip/single_read.py | 2 +- tests/protocols_tests.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index bf580ca..e5cff31 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -8,7 +8,7 @@ import argparse # TODO: check if it is too slow at runtime import sys -from pycomm.clx import Driver as ClxDriver +from pycomm.ab_comm.clx import Driver as ClxDriver def read_tag(address, tag_name): plc = ClxDriver() diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index 7492f52..4add061 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -156,21 +156,21 @@ def test_receive_multikey(self): # read a multikey what = ('SENSOR1', 1) address = 'localhost:44818' - eq_(enip._receive(what, ADDRESS), "0\n") + eq_(enip._receive(what, ADDRESS), "0") # read a multi key what = ('ACTUATOR1',1) address = 'localhost:44818' - eq_(enip._receive(what, ADDRESS), "0\n") + eq_(enip._receive(what, ADDRESS), "0") # Read a single key - uninitialized tag what = ('HMI_TEST101',) address = 'localhost:44818' - eq_(enip._receive(what, ADDRESS), "check server log.\n") + eq_(enip._receive(what, ADDRESS), "check server log.") # Read a multi key what = ('FLAG101', 2) - eq_(enip._receive(what, ADDRESS), 'enipserver\n') + eq_(enip._receive(what, ADDRESS), 'enipserver') EnipProtocol._stop_server(server) @@ -193,23 +193,23 @@ def test_client_server(self): # read a multikey what = ('SENSOR1', 1) - eq_(enip._receive(what, ADDRESS), '0\n') + eq_(enip._receive(what, ADDRESS), '0') # read a single key what = ('ACTUATOR1',) - eq_(enip._receive(what, ADDRESS), '0\n') + eq_(enip._receive(what, ADDRESS), '0') # read a single key - present tag what = ('HMI_TEST101',) - eq_(enip._receive(what, ADDRESS), "check server log.\n") + eq_(enip._receive(what, ADDRESS), "check server log.") # read a single key what = ('FLAG101',) - eq_(enip._receive(what, ADDRESS),'enipserver\n') + eq_(enip._receive(what, ADDRESS),'enipserver') # read a single key what = ('FLAG201', 2) - eq_(enip._receive(what, ADDRESS),'enipserver\n') + eq_(enip._receive(what, ADDRESS),'enipserver') # write a multikey what = ('SENSOR1', 1) From e34a4c0431c3219e70d8f0a6e1ba6f92b484f69d Mon Sep 17 00:00:00 2001 From: remmihsorp Date: Mon, 24 Jul 2017 18:29:35 +0800 Subject: [PATCH 27/31] updated protocol to include restructured enipserver codebase --- minicps/protocols.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index c12e2b5..087e4a7 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -226,23 +226,18 @@ def _start_server_cmd(cls, address='localhost:44818', if address.find(":") != -1: address = address.split(":")[0] - VERBOSE = '-v ' - ADDRESS = '--address ' + address + ' ' TAGS = cls._nested_tuples_to_enip_tags(tags) + ADDRESS = '--tcpadd ' + address + ' ' ENV = "python3" - CMD = " -m enipserver.server " + CMD = " -m enipserver.main " - if sys.platform.startswith('linux'): - LOG = '--log logs/protocols_tests_enip_server ' - else: + if not sys.platform.startswith('linux'): raise OSError cmd = shlex.split( ENV + CMD + - VERBOSE + - LOG + ADDRESS + TAGS ) @@ -263,7 +258,6 @@ def _start_server(cls, address, tags): try: cmd = cls._start_server_cmd(address, tags) cls.server = subprocess.Popen(cmd, shell=False) - return cls.server except Exception as error: @@ -323,7 +317,8 @@ def infer_tag_type(val): stdout=subprocess.PIPE) # client.communicate is blocking - client.wait() + raw_out = client.communicate() + return raw_out[0] except Exception as error: print 'ERROR enip _send: ', error From d746be9b2e8a72534feb92adc0825fc8ea45e67a Mon Sep 17 00:00:00 2001 From: remmihsorp Date: Mon, 24 Jul 2017 18:30:57 +0800 Subject: [PATCH 28/31] removed debugging comments --- minicps/protocols.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index 087e4a7..a132754 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -26,8 +26,8 @@ from multiprocessing import Process -#import cpppo -#import pymodbus +import cpppo +import pymodbus # Protocol {{{1 class Protocol(object): @@ -357,8 +357,6 @@ def _receive(self, what, address='localhost'): # client.communicate is blocking raw_out = client.communicate() # print 'DEBUG enip _receive raw_out: ', raw_out - - # value is stored as first tuple element return raw_out[0] except Exception as error: From 866e981cb8d1d09614d13af3adcb04739b392163 Mon Sep 17 00:00:00 2001 From: remmihsorp Date: Mon, 24 Jul 2017 18:32:10 +0800 Subject: [PATCH 29/31] refactored bridging script to give appropriate responses --- minicps/pyenip/single_read.py | 34 ++++++++++------------------------ minicps/pyenip/single_write.py | 30 ++++++++++++------------------ 2 files changed, 22 insertions(+), 42 deletions(-) diff --git a/minicps/pyenip/single_read.py b/minicps/pyenip/single_read.py index e5cff31..865bed8 100755 --- a/minicps/pyenip/single_read.py +++ b/minicps/pyenip/single_read.py @@ -1,26 +1,17 @@ #!/usr/bin/python2 -""" -synch-client.py - -value is passed either as a ``str`` or as a ``bool``. In case of ``str`` the value is -converted to an ``int`` to be written in a holding register -""" - -import argparse # TODO: check if it is too slow at runtime +import argparse import sys from pycomm.ab_comm.clx import Driver as ClxDriver def read_tag(address, tag_name): plc = ClxDriver() - try: - if plc.open(address): - tagg = plc.read_tag(tag_name) - plc.close() - return (tagg) - else: - return ("u", ) - except Exception as e: - raise ValueError(e) + if plc.open(address): + tagg = plc.read_tag(tag_name) + plc.close() + return (tagg) + else: + return "false" + if __name__ == "__main__": @@ -42,10 +33,5 @@ def read_tag(address, tag_name): res = read_tag(address, tag_name) - val = res[0] - - if val == "u" or res[1] == 'Check Encapsulation and Message Router Error': - sys.stdout.write('check server log.') - else: - sys.stdout.write("%s" % val) - + val = "err" if (res is None or res=="false") else res[0] + sys.stdout.write("%s" % val) diff --git a/minicps/pyenip/single_write.py b/minicps/pyenip/single_write.py index 3deff1b..fb74df9 100755 --- a/minicps/pyenip/single_write.py +++ b/minicps/pyenip/single_write.py @@ -1,13 +1,7 @@ #!/usr/bin/python2 -""" -single_write.py - -value is passed as a ``str`` -""" - -import argparse # TODO: check if it is too slow at runtime import sys +import argparse from pycomm.ab_comm.clx import Driver as ClxDriver def convert_value_to_proper_type(tag_type, val): @@ -21,15 +15,12 @@ def convert_value_to_proper_type(tag_type, val): def write_tag(tag_name, value, tag_type): plc = ClxDriver() - try: - if plc.open(address): - temp = plc.write_tag(tag_name, value, tag_type) - plc.close() - return temp - else: - return "u" - except Exception as e: - raise Exception(e) + if plc.open(address): + temp = plc.write_tag(tag_name, value, tag_type) + plc.close() + return temp + else: + return "false" if __name__ == "__main__": @@ -56,9 +47,12 @@ def write_tag(tag_name, value, tag_type): # retrieve the ip and ignore the port address = args.ip.split(":")[0] - if tag_type not in ["INT", "STRING", "REAL"]: + if tag_type not in ["INT", "STRING", "REAL", "BOOL"]: print("single_write.py: error: tag type is invalid.") print("usage: single_write.py -h for help") - raise ValueError("single_write.py: error: tag type is invalid. Only INT, STRING, and FLOAT is supported.") + raise ValueError("single_write.py: error: tag type is invalid. Only INT, STRING, BOOL, and REAL is supported.") res = write_tag(tag_name, value, tag_type) + + val = "err" if (res is None or res=="false") else res + sys.stdout.write("%s" % res) From c3222e2c67328ebee3f76d7f31130dc85494390d Mon Sep 17 00:00:00 2001 From: remmihsorp Date: Mon, 24 Jul 2017 18:34:06 +0800 Subject: [PATCH 30/31] added sleep(1) to wait for the server to start; added test to check for proper write requests --- tests/protocols_tests.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/protocols_tests.py b/tests/protocols_tests.py index 4add061..a896303 100644 --- a/tests/protocols_tests.py +++ b/tests/protocols_tests.py @@ -64,6 +64,7 @@ def test_server_start_stop(self): try: server = EnipProtocol._start_server(ADDRESS, TAGS) + time.sleep(1) EnipProtocol._stop_server(server) except Exception as error: @@ -86,6 +87,7 @@ def test_init_server(self): try: server = EnipProtocol( protocol=TestEnipProtocol.CLIENT_SERVER_PROTOCOL) + time.sleep(1) eq_(server._name, 'enip') server._stop_server(server._server_subprocess) del server @@ -99,6 +101,7 @@ def test_server_multikey(self): TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT'), ('FLAG2', 2, 'STRING')) try: server = EnipProtocol._start_server(ADDRESS, TAGS) + time.sleep(1) EnipProtocol._stop_server(server) except Exception as error: print 'ERROR test_server_multikey: ', error @@ -118,22 +121,22 @@ def test_send_multikey(self): # write a multikey what = ('SENSOR1', 1) for value in range(5): - enip._send(what, value, ADDRESS) + eq_(enip._send(what, value, ADDRESS), str(True)) # write a multi key what = ('ACTUATOR1', 1) for value in range(5): - enip._send(what, 1, ADDRESS) + eq_(enip._send(what, 1, ADDRESS), str(True)) # write a multi key what = ('FLAG101', 2) for value in range(5): - enip._send(what, chr(127-value)*6, ADDRESS) + eq_(enip._send(what, chr(127-value)*6, ADDRESS), str(True)) # write a multi key what = ('HMI_TEST101',) for value in range(5): - enip._send(what, 1, ADDRESS) + eq_(enip._send(what, 1, ADDRESS), str(False)) EnipProtocol._stop_server(server) except Exception as error: @@ -166,11 +169,11 @@ def test_receive_multikey(self): # Read a single key - uninitialized tag what = ('HMI_TEST101',) address = 'localhost:44818' - eq_(enip._receive(what, ADDRESS), "check server log.") + eq_(enip._receive(what, ADDRESS), "err") # Read a multi key what = ('FLAG101', 2) - eq_(enip._receive(what, ADDRESS), 'enipserver') + eq_(enip._receive(what, ADDRESS), 'ENIPSERVER') EnipProtocol._stop_server(server) @@ -199,42 +202,42 @@ def test_client_server(self): what = ('ACTUATOR1',) eq_(enip._receive(what, ADDRESS), '0') - # read a single key - present tag + # read a single key - missing tag what = ('HMI_TEST101',) - eq_(enip._receive(what, ADDRESS), "check server log.") + eq_(enip._receive(what, ADDRESS), "err") # read a single key what = ('FLAG101',) - eq_(enip._receive(what, ADDRESS),'enipserver') + eq_(enip._receive(what, ADDRESS),'ENIPSERVER') # read a single key what = ('FLAG201', 2) - eq_(enip._receive(what, ADDRESS),'enipserver') + eq_(enip._receive(what, ADDRESS),'ENIPSERVER') # write a multikey what = ('SENSOR1', 1) for value in range(5): - enip._send(what, value, ADDRESS) + eq_(enip._send(what, value, ADDRESS), str(True)) # write a single key what = ('ACTUATOR1',) for value in range(5): - enip._send(what, value, ADDRESS) + eq_(enip._send(what, value, ADDRESS), str(True)) # write a single key - uninitialized tag - error shouldn't occur what = ('HMI_TEST101') for value in range(5): - enip._send(what, value, ADDRESS) + eq_(enip._send(what, value, ADDRESS), str(False)) # write a single key - what = ('FLAG101') + what = ('FLAG101',) for value in range(5): - enip._send(what, str(127-value)*8, ADDRESS) + eq_(enip._send(what, str(127-value)*8, ADDRESS), str(True)) # write a multi key what = ('FLAG201', 2) for value in range(5): - enip._send(what, chr(127-value)*8, ADDRESS) + eq_(enip._send(what, chr(127-value)*8, ADDRESS), str(True)) EnipProtocol._stop_server(enip._server_subprocess) From a4e7d862ba47dd79bdba081918ec34da4b4e9445 Mon Sep 17 00:00:00 2001 From: remmihsorp Date: Mon, 7 Aug 2017 23:08:08 +0800 Subject: [PATCH 31/31] updated enip protocol start server since enipserver package was restructured --- minicps/protocols.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/minicps/protocols.py b/minicps/protocols.py index a132754..946f58e 100644 --- a/minicps/protocols.py +++ b/minicps/protocols.py @@ -205,7 +205,7 @@ def _nested_tuples_to_enip_tags(cls, tags): for tag in tags: tag = [str(x) for x in tag] tag_list.append("{0}@{1}".format(':'.join(tag[:-1]), tag[-1])) - return '--tags ' + ' '.join(tag_list) + return ' '.join(tag_list) @classmethod def _start_server_cmd(cls, address='localhost:44818', @@ -226,8 +226,8 @@ def _start_server_cmd(cls, address='localhost:44818', if address.find(":") != -1: address = address.split(":")[0] - TAGS = cls._nested_tuples_to_enip_tags(tags) - ADDRESS = '--tcpadd ' + address + ' ' + ADDRESS = '-i ' + address + ' ' + TAGS = '-t ' + cls._nested_tuples_to_enip_tags(tags) ENV = "python3" CMD = " -m enipserver.main "