modbus/modbus.py
changeset 1919 ccea0fa6ea91
parent 1918 e7b6478b4ebc
child 2019 92f02bb17c7e
child 2179 84c4e56b38d6
equal deleted inserted replaced
1918:e7b6478b4ebc 1919:ccea0fa6ea91
    21 #
    21 #
    22 # This code is made available on the understanding that it will not be
    22 # This code is made available on the understanding that it will not be
    23 # used in safety-critical situations without a full and competent review.
    23 # used in safety-critical situations without a full and competent review.
    24 
    24 
    25 
    25 
       
    26 from __future__ import absolute_import
    26 import os
    27 import os
    27 import sys
    28 from modbus.mb_utils import *
    28 from mb_utils import *
    29 
    29 
       
    30 import wx
       
    31 from ConfigTreeNode import ConfigTreeNode
    30 from ConfigTreeNode import ConfigTreeNode
    32 from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    31 from PLCControler import LOCATION_CONFNODE, LOCATION_VAR_MEMORY
    33 
    32 
    34 base_folder = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
    33 base_folder = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
    35 base_folder = os.path.join(base_folder, "..")
    34 base_folder = os.path.join(base_folder, "..")
    36 ModbusPath = os.path.join(base_folder, "Modbus")
    35 ModbusPath = os.path.join(base_folder, "Modbus")
    37 
    36 
    43 #
    42 #
    44 #
    43 #
    45 #
    44 #
    46 
    45 
    47 
    46 
    48 class _RequestPlug:
    47 class _RequestPlug(object):
    49     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
    48     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
    50     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    49     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    51       <xsd:element name="ModbusRequest">
    50       <xsd:element name="ModbusRequest">
    52         <xsd:complexType>
    51         <xsd:complexType>
    53           <xsd:attribute name="Function" type="xsd:string" use="optional" default="01 - Read Coils"/>
    52           <xsd:attribute name="Function" type="xsd:string" use="optional" default="01 - Read Coils"/>
   108         # 'BOOL' or 'WORD'
   107         # 'BOOL' or 'WORD'
   109         datatype = modbus_function_dict[function][3]
   108         datatype = modbus_function_dict[function][3]
   110         # 1 or 16
   109         # 1 or 16
   111         datasize = modbus_function_dict[function][4]
   110         datasize = modbus_function_dict[function][4]
   112         # 'Q' for coils and holding registers, 'I' for input discretes and input registers
   111         # 'Q' for coils and holding registers, 'I' for input discretes and input registers
   113         datazone = modbus_function_dict[function][5]
   112         # datazone = modbus_function_dict[function][5]
   114         # 'X' for bits, 'W' for words
   113         # 'X' for bits, 'W' for words
   115         datatacc = modbus_function_dict[function][6]
   114         datatacc = modbus_function_dict[function][6]
   116         # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register'
   115         # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register'
   117         dataname = modbus_function_dict[function][7]
   116         dataname = modbus_function_dict[function][7]
   118         entries = []
   117         entries = []
   164     "03 - Holding Registers": ('3', 'rw_words', 65536, "WORD", 16, "Q", "W", "Holding Register"),
   163     "03 - Holding Registers": ('3', 'rw_words', 65536, "WORD", 16, "Q", "W", "Holding Register"),
   165     "04 - Input Registers":  ('4', 'ro_words', 65536, "WORD", 16, "I", "W", "Input Register"),
   164     "04 - Input Registers":  ('4', 'ro_words', 65536, "WORD", 16, "I", "W", "Input Register"),
   166 }
   165 }
   167 
   166 
   168 
   167 
   169 class _MemoryAreaPlug:
   168 class _MemoryAreaPlug(object):
   170     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   169     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   171     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   170     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   172       <xsd:element name="MemoryArea">
   171       <xsd:element name="MemoryArea">
   173         <xsd:complexType>
   172         <xsd:complexType>
   174           <xsd:attribute name="MemoryAreaType" type="xsd:string" use="optional" default="01 - Coils"/>
   173           <xsd:attribute name="MemoryAreaType" type="xsd:string" use="optional" default="01 - Coils"/>
   213         # 'BOOL' or 'WORD'
   212         # 'BOOL' or 'WORD'
   214         datatype = modbus_memtype_dict[function][3]
   213         datatype = modbus_memtype_dict[function][3]
   215         # 1 or 16
   214         # 1 or 16
   216         datasize = modbus_memtype_dict[function][4]
   215         datasize = modbus_memtype_dict[function][4]
   217         # 'Q' for coils and holding registers, 'I' for input discretes and input registers
   216         # 'Q' for coils and holding registers, 'I' for input discretes and input registers
   218         datazone = modbus_memtype_dict[function][5]
   217         # datazone = modbus_memtype_dict[function][5]
   219         # 'X' for bits, 'W' for words
   218         # 'X' for bits, 'W' for words
   220         datatacc = modbus_memtype_dict[function][6]
   219         datatacc = modbus_memtype_dict[function][6]
   221         # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register'
   220         # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register'
   222         dataname = modbus_memtype_dict[function][7]
   221         dataname = modbus_memtype_dict[function][7]
   223         entries = []
   222         entries = []
   258 # T C P    C L I E N T                 #
   257 # T C P    C L I E N T                 #
   259 #
   258 #
   260 #
   259 #
   261 #
   260 #
   262 
   261 
   263 class _ModbusTCPclientPlug:
   262 class _ModbusTCPclientPlug(object):
   264     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   263     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   265     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   264     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   266       <xsd:element name="ModbusTCPclient">
   265       <xsd:element name="ModbusTCPclient">
   267         <xsd:complexType>
   266         <xsd:complexType>
   268           <xsd:attribute name="Remote_IP_Address" type="xsd:string" use="optional" default="localhost"/>
   267           <xsd:attribute name="Remote_IP_Address" type="xsd:string" use="optional" default="localhost"/>
   312 # T C P    S E R V E R                 #
   311 # T C P    S E R V E R                 #
   313 #
   312 #
   314 #
   313 #
   315 #
   314 #
   316 
   315 
   317 class _ModbusTCPserverPlug:
   316 class _ModbusTCPserverPlug(object):
   318     # NOTE: the Port number is a 'string' and not an 'integer'!
   317     # NOTE: the Port number is a 'string' and not an 'integer'!
   319     # This is because the underlying modbus library accepts strings
   318     # This is because the underlying modbus library accepts strings
   320     # (e.g.: well known port names!)
   319     # (e.g.: well known port names!)
   321     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   320     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   322     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   321     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   374 # R T U    C L I E N T                 #
   373 # R T U    C L I E N T                 #
   375 #
   374 #
   376 #
   375 #
   377 #
   376 #
   378 
   377 
   379 class _ModbusRTUclientPlug:
   378 class _ModbusRTUclientPlug(object):
   380     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   379     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   381     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   380     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   382       <xsd:element name="ModbusRTUclient">
   381       <xsd:element name="ModbusRTUclient">
   383         <xsd:complexType>
   382         <xsd:complexType>
   384           <xsd:attribute name="Serial_Port" type="xsd:string"  use="optional" default="/dev/ttyS0"/>
   383           <xsd:attribute name="Serial_Port" type="xsd:string"  use="optional" default="/dev/ttyS0"/>
   444 #
   443 #
   445 #
   444 #
   446 #
   445 #
   447 
   446 
   448 
   447 
   449 class _ModbusRTUslavePlug:
   448 class _ModbusRTUslavePlug(object):
   450     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   449     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   451     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   450     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   452       <xsd:element name="ModbusRTUslave">
   451       <xsd:element name="ModbusRTUslave">
   453         <xsd:complexType>
   452         <xsd:complexType>
   454           <xsd:attribute name="Serial_Port" type="xsd:string"  use="optional" default="/dev/ttyS0"/>
   453           <xsd:attribute name="Serial_Port" type="xsd:string"  use="optional" default="/dev/ttyS0"/>
   514 #
   513 #
   515 # R O O T    C L A S S                #
   514 # R O O T    C L A S S                #
   516 #
   515 #
   517 #
   516 #
   518 #
   517 #
   519 class RootClass:
   518 class RootClass(object):
   520     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   519     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   521     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   520     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   522       <xsd:element name="ModbusRoot">
   521       <xsd:element name="ModbusRoot">
   523         <xsd:complexType>
   522         <xsd:complexType>
   524           <xsd:attribute name="MaxRemoteTCPclients" use="optional" default="10">
   523           <xsd:attribute name="MaxRemoteTCPclients" use="optional" default="10">
   531           </xsd:attribute>
   530           </xsd:attribute>
   532         </xsd:complexType>
   531         </xsd:complexType>
   533       </xsd:element>
   532       </xsd:element>
   534     </xsd:schema>
   533     </xsd:schema>
   535     """
   534     """
   536     CTNChildrenTypes = [("ModbusTCPclient", _ModbusTCPclientPlug, "Modbus TCP Client"), ("ModbusTCPserver", _ModbusTCPserverPlug, "Modbus TCP Server"), ("ModbusRTUclient", _ModbusRTUclientPlug, "Modbus RTU Client"), ("ModbusRTUslave", _ModbusRTUslavePlug,  "Modbus RTU Slave")
   535     CTNChildrenTypes = [("ModbusTCPclient", _ModbusTCPclientPlug, "Modbus TCP Client"),
   537                         ]
   536                         ("ModbusTCPserver", _ModbusTCPserverPlug, "Modbus TCP Server"),
       
   537                         ("ModbusRTUclient", _ModbusRTUclientPlug, "Modbus RTU Client"),
       
   538                         ("ModbusRTUslave", _ModbusRTUslavePlug,  "Modbus RTU Slave")]
   538 
   539 
   539     # Return the number of (modbus library) nodes this specific instance of the modbus plugin will need
   540     # Return the number of (modbus library) nodes this specific instance of the modbus plugin will need
   540     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   541     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   541     def GetNodeCount(self):
   542     def GetNodeCount(self):
   542         max_remote_tcpclient = self.GetParamsAttributes()[
   543         max_remote_tcpclient = self.GetParamsAttributes()[
   565         # print self.CTNType
   566         # print self.CTNType
   566         # print "type(self.CTNType) >>>"
   567         # print "type(self.CTNType) >>>"
   567         # print type(self.CTNType)
   568         # print type(self.CTNType)
   568         # print "#############"
   569         # print "#############"
   569 
   570 
   570         loc_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation())),
   571         loc_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation()))}
   571                     }
       
   572 
   572 
   573         # Determine the number of (modbus library) nodes ALL instances of the modbus plugin will need
   573         # Determine the number of (modbus library) nodes ALL instances of the modbus plugin will need
   574         #   total_node_count: (tcp nodes, rtu nodes, ascii nodes)
   574         #   total_node_count: (tcp nodes, rtu nodes, ascii nodes)
   575         # Also get a list with tuples of (location, IP port numbers) used by all the Modbus/IP server nodes
   575         # Also get a list with tuples of (location, IP port numbers) used by all the Modbus/IP server nodes
   576         #   This list is later used to search for duplicates in port numbers!
   576         #   This list is later used to search for duplicates in port numbers!
   661                     # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
   661                     # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
   662                     memarea = modbus_memtype_dict[function][1]
   662                     memarea = modbus_memtype_dict[function][1]
   663                     for iecvar in subchild.GetLocations():
   663                     for iecvar in subchild.GetLocations():
   664                         # print repr(iecvar)
   664                         # print repr(iecvar)
   665                         absloute_address = iecvar["LOC"][3]
   665                         absloute_address = iecvar["LOC"][3]
   666                         start_address = int(GetCTVal(child, 2))
   666                         start_address = int(GetCTVal(subchild, 2))
   667                         relative_addr = absloute_address - start_address
   667                         relative_addr = absloute_address - start_address
   668                         # test if relative address in request specified range
   668                         # test if relative address in request specified range
   669                         if relative_addr in xrange(int(GetCTVal(child, 1))):
   669                         if relative_addr in xrange(int(GetCTVal(subchild, 1))):
   670                             if str(iecvar["NAME"]) not in loc_vars_list:
   670                             if str(iecvar["NAME"]) not in loc_vars_list:
   671                                 loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
   671                                 loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
   672                                     server_id, memarea, absloute_address))
   672                                     server_id, memarea, absloute_address))
   673                                 loc_vars_list.append(str(iecvar["NAME"]))
   673                                 loc_vars_list.append(str(iecvar["NAME"]))
   674                 server_id += 1
   674                 server_id += 1
   691                     # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
   691                     # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
   692                     memarea = modbus_memtype_dict[function][1]
   692                     memarea = modbus_memtype_dict[function][1]
   693                     for iecvar in subchild.GetLocations():
   693                     for iecvar in subchild.GetLocations():
   694                         # print repr(iecvar)
   694                         # print repr(iecvar)
   695                         absloute_address = iecvar["LOC"][3]
   695                         absloute_address = iecvar["LOC"][3]
   696                         start_address = int(GetCTVal(child, 2))
   696                         start_address = int(GetCTVal(subchild, 2))
   697                         relative_addr = absloute_address - start_address
   697                         relative_addr = absloute_address - start_address
   698                         # test if relative address in request specified range
   698                         # test if relative address in request specified range
   699                         if relative_addr in xrange(int(GetCTVal(child, 1))):
   699                         if relative_addr in xrange(int(GetCTVal(subchild, 1))):
   700                             if str(iecvar["NAME"]) not in loc_vars_list:
   700                             if str(iecvar["NAME"]) not in loc_vars_list:
   701                                 loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
   701                                 loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
   702                                     server_id, memarea, absloute_address))
   702                                     server_id, memarea, absloute_address))
   703                                 loc_vars_list.append(str(iecvar["NAME"]))
   703                                 loc_vars_list.append(str(iecvar["NAME"]))
   704                 server_id += 1
   704                 server_id += 1
   715                     if new_req is None:
   715                     if new_req is None:
   716                         return [], "", False
   716                         return [], "", False
   717                     client_request_list.append(new_req)
   717                     client_request_list.append(new_req)
   718                     for iecvar in subchild.GetLocations():
   718                     for iecvar in subchild.GetLocations():
   719                         # absloute address - start address
   719                         # absloute address - start address
   720                         relative_addr = iecvar["LOC"][3] - int(GetCTVal(child, 3))
   720                         relative_addr = iecvar["LOC"][3] - int(GetCTVal(subchild, 3))
   721                         # test if relative address in request specified range
   721                         # test if relative address in request specified range
   722                         if relative_addr in xrange(int(GetCTVal(child, 2))):
   722                         if relative_addr in xrange(int(GetCTVal(subchild, 2))):
   723                             if str(iecvar["NAME"]) not in loc_vars_list:
   723                             if str(iecvar["NAME"]) not in loc_vars_list:
   724                                 loc_vars.append(
   724                                 loc_vars.append(
   725                                     "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
   725                                     "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
   726                                 loc_vars_list.append(str(iecvar["NAME"]))
   726                                 loc_vars_list.append(str(iecvar["NAME"]))
   727                     client_requestid += 1
   727                     client_requestid += 1
   740                     if new_req is None:
   740                     if new_req is None:
   741                         return [], "", False
   741                         return [], "", False
   742                     client_request_list.append(new_req)
   742                     client_request_list.append(new_req)
   743                     for iecvar in subchild.GetLocations():
   743                     for iecvar in subchild.GetLocations():
   744                         # absloute address - start address
   744                         # absloute address - start address
   745                         relative_addr = iecvar["LOC"][3] - int(GetCTVal(child, 3))
   745                         relative_addr = iecvar["LOC"][3] - int(GetCTVal(subchild, 3))
   746                         # test if relative address in request specified range
   746                         # test if relative address in request specified range
   747                         if relative_addr in xrange(int(GetCTVal(child, 2))):
   747                         if relative_addr in xrange(int(GetCTVal(subchild, 2))):
   748                             if str(iecvar["NAME"]) not in loc_vars_list:
   748                             if str(iecvar["NAME"]) not in loc_vars_list:
   749                                 loc_vars.append(
   749                                 loc_vars.append(
   750                                     "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
   750                                     "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
   751                                 loc_vars_list.append(str(iecvar["NAME"]))
   751                                 loc_vars_list.append(str(iecvar["NAME"]))
   752                     client_requestid += 1
   752                     client_requestid += 1