modbus/modbus.py
changeset 2668 cca3e5d7d6f3
parent 2663 54f5b8e5c8d2
child 2669 be233279d179
child 2713 680ea4684209
equal deleted inserted replaced
2659:09bac1f52b1e 2668:cca3e5d7d6f3
   330     # Return the number of (modbus library) nodes this specific TCP client will need
   330     # Return the number of (modbus library) nodes this specific TCP client will need
   331     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   331     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   332     def GetNodeCount(self):
   332     def GetNodeCount(self):
   333         return (1, 0, 0)
   333         return (1, 0, 0)
   334 
   334 
       
   335     def GetConfigName(self):
       
   336         """ Return the node's Configuration_Name """
       
   337         return self.ModbusTCPclient.getConfiguration_Name()
       
   338 
   335     def CTNGenerate_C(self, buildpath, locations):
   339     def CTNGenerate_C(self, buildpath, locations):
   336         """
   340         """
   337         Generate C code
   341         Generate C code
   338         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   342         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   339         @param locations: List of complete variables locations \
   343         @param locations: List of complete variables locations \
   403     # Return the number of (modbus library) nodes this specific TCP server will need
   407     # Return the number of (modbus library) nodes this specific TCP server will need
   404     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   408     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   405     def GetNodeCount(self):
   409     def GetNodeCount(self):
   406         return (1, 0, 0)
   410         return (1, 0, 0)
   407 
   411 
   408     # Return a list with a single tuple conatining the (location, port number)
   412     # Return a list with a single tuple conatining the (location, IP address, port number)
   409     #     location: location of this node in the configuration tree
   413     #     location   : location of this node in the configuration tree
   410     #     port number: IP port used by this Modbus/IP server
   414     #     port number: IP port used by this Modbus/IP server
       
   415     #     IP address : IP address of the network interface on which the server will be listening
       
   416     #                  ("", "*", or "#ANY#" => listening on all interfaces!)
   411     def GetIPServerPortNumbers(self):
   417     def GetIPServerPortNumbers(self):
   412         port = self.GetParamsAttributes()[0]["children"][1]["value"]
   418         port = self.ModbusServerNode.getLocal_Port_Number()
   413         return [(self.GetCurrentLocation(), port)]
   419         addr = self.ModbusServerNode.getLocal_IP_Address()
       
   420         return [(self.GetCurrentLocation(), addr, port)]
       
   421 
       
   422     def GetConfigName(self):
       
   423         """ Return the node's Configuration_Name """
       
   424         return self.ModbusServerNode.getConfiguration_Name()
   414 
   425 
   415     def CTNGenerate_C(self, buildpath, locations):
   426     def CTNGenerate_C(self, buildpath, locations):
   416         """
   427         """
   417         Generate C code
   428         Generate C code
   418         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   429         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   497     # Return the number of (modbus library) nodes this specific RTU client will need
   508     # Return the number of (modbus library) nodes this specific RTU client will need
   498     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   509     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   499     def GetNodeCount(self):
   510     def GetNodeCount(self):
   500         return (0, 1, 0)
   511         return (0, 1, 0)
   501 
   512 
       
   513     def GetConfigName(self):
       
   514         """ Return the node's Configuration_Name """
       
   515         return self.ModbusRTUclient.getConfiguration_Name()
       
   516 
   502     def CTNGenerate_C(self, buildpath, locations):
   517     def CTNGenerate_C(self, buildpath, locations):
   503         """
   518         """
   504         Generate C code
   519         Generate C code
   505         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   520         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   506         @param locations: List of complete variables locations \
   521         @param locations: List of complete variables locations \
   583     # Return the number of (modbus library) nodes this specific RTU slave will need
   598     # Return the number of (modbus library) nodes this specific RTU slave will need
   584     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   599     #   return type: (tcp nodes, rtu nodes, ascii nodes)
   585     def GetNodeCount(self):
   600     def GetNodeCount(self):
   586         return (0, 1, 0)
   601         return (0, 1, 0)
   587 
   602 
       
   603     def GetConfigName(self):
       
   604         """ Return the node's Configuration_Name """
       
   605         return self.ModbusRTUslave.getConfiguration_Name()
       
   606 
   588     def CTNGenerate_C(self, buildpath, locations):
   607     def CTNGenerate_C(self, buildpath, locations):
   589         """
   608         """
   590         Generate C code
   609         Generate C code
   591         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   610         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   592         @param locations: List of complete variables locations \
   611         @param locations: List of complete variables locations \
   644             # ask each child how many nodes it needs, and add them all up.
   663             # ask each child how many nodes it needs, and add them all up.
   645             total_node_count = tuple(
   664             total_node_count = tuple(
   646                 x1 + x2 for x1, x2 in zip(total_node_count, child.GetNodeCount()))
   665                 x1 + x2 for x1, x2 in zip(total_node_count, child.GetNodeCount()))
   647         return total_node_count
   666         return total_node_count
   648 
   667 
   649     # Return a list with tuples of the (location, port numbers) used by all
   668     # Return a list with tuples of the (location, port numbers) used by all the Modbus/IP servers
   650     # the Modbus/IP servers
       
   651     def GetIPServerPortNumbers(self):
   669     def GetIPServerPortNumbers(self):
   652         IPServer_port_numbers = []
   670         IPServer_port_numbers = []
   653         for child in self.IECSortedChildren():
   671         for child in self.IECSortedChildren():
   654             if child.CTNType == "ModbusTCPserver":
   672             if child.CTNType == "ModbusTCPserver":
   655                 IPServer_port_numbers.extend(child.GetIPServerPortNumbers())
   673                 IPServer_port_numbers.extend(child.GetIPServerPortNumbers())
   656         return IPServer_port_numbers
   674         return IPServer_port_numbers
       
   675 
       
   676     # Return a list with tuples of the (location, configuration_name) used by all the Modbus nodes (tcp/rtu, clients/servers)
       
   677     def GetConfigNames(self):
       
   678         Node_Configuration_Names = []
       
   679         for child in self.IECSortedChildren():
       
   680             Node_Configuration_Names.extend([(child.GetCurrentLocation(), child.GetConfigName())])
       
   681         return Node_Configuration_Names
   657 
   682 
   658     def CTNGenerate_C(self, buildpath, locations):
   683     def CTNGenerate_C(self, buildpath, locations):
   659         # print "#############"
   684         # print "#############"
   660         # print self.__class__
   685         # print self.__class__
   661         # print type(self)
   686         # print type(self)
   667 
   692 
   668         loc_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation()))}
   693         loc_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation()))}
   669 
   694 
   670         # Determine the number of (modbus library) nodes ALL instances of the modbus plugin will need
   695         # Determine the number of (modbus library) nodes ALL instances of the modbus plugin will need
   671         #   total_node_count: (tcp nodes, rtu nodes, ascii nodes)
   696         #   total_node_count: (tcp nodes, rtu nodes, ascii nodes)
   672         # Also get a list with tuples of (location, IP port numbers) used by all the Modbus/IP server nodes
   697         #
       
   698         # Also get a list with tuples of (location, IP address, port number) used by all the Modbus/IP server nodes
   673         #   This list is later used to search for duplicates in port numbers!
   699         #   This list is later used to search for duplicates in port numbers!
   674         #   IPServer_port_numbers = [(location ,IPserver_port_number), ...]
   700         #   IPServer_port_numbers = [(location, IP address, port number), ...]
   675         #       location: tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x"
   701         #       location            : tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x"
   676         # IPserver_port_number: a number (i.e. port number used by the
   702         #       IPserver_port_number: a number (i.e. port number used by the Modbus/IP server)
   677         # Modbus/IP server)
   703         #       IP address          : IP address of the network interface on which the server will be listening
       
   704         #                             ("", "*", or "#ANY#" => listening on all interfaces!)
       
   705         #
       
   706         # Also get a list with tuples of (location, Configuration_Name) used by all the Modbus nodes
       
   707         #   This list is later used to search for duplicates in Configuration Names!
       
   708         #   Node_Configuration_Names = [(location, Configuration_Name), ...]
       
   709         #       location          : tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x"
       
   710         #       Configuration_Name: the "Configuration_Name" string
   678         total_node_count = (0, 0, 0)
   711         total_node_count = (0, 0, 0)
   679         IPServer_port_numbers = []
   712         IPServer_port_numbers    = []
       
   713         Node_Configuration_Names = []
   680         for CTNInstance in self.GetCTRoot().IterChildren():
   714         for CTNInstance in self.GetCTRoot().IterChildren():
   681             if CTNInstance.CTNType == "modbus":
   715             if CTNInstance.CTNType == "modbus":
   682                 # ask each modbus plugin instance how many nodes it needs, and
   716                 # ask each modbus plugin instance how many nodes it needs, and add them all up.
   683                 # add them all up.
   717                 total_node_count = tuple(x1 + x2 for x1, x2 in zip(total_node_count, CTNInstance.GetNodeCount()))
   684                 total_node_count = tuple(x1 + x2 for x1, x2 in zip(
   718                 IPServer_port_numbers.   extend(CTNInstance.GetIPServerPortNumbers())
   685                     total_node_count, CTNInstance.GetNodeCount()))
   719                 Node_Configuration_Names.extend(CTNInstance.GetConfigNames        ())
   686                 IPServer_port_numbers.extend(
   720 
   687                     CTNInstance.GetIPServerPortNumbers())
   721         # Search for use of duplicate Configuration_Names by Modbus nodes
       
   722         # Configuration Names are used by the web server running on the PLC
       
   723         # (more precisely, run by Beremiz_service.py) to identify and allow 
       
   724         # changing the Modbus parameters after the program has been downloaded 
       
   725         # to the PLC (but before it is started)
       
   726         # With clashes in the configuration names, the Modbus nodes will not be
       
   727         # distinguasheble on the web interface!
       
   728         for i in range(0, len(Node_Configuration_Names) - 1):
       
   729             for j in range(i + 1, len(Node_Configuration_Names)):
       
   730                 if Node_Configuration_Names[i][1] == Node_Configuration_Names[j][1]:
       
   731                     error_message = _("Error: Modbus plugin nodes %{a1}.x and %{a2}.x use the same Configuration_Name \"{a3}\".\n").format(
       
   732                                         a1=_lt_to_str(Node_Configuration_Names[i][0]),
       
   733                                         a2=_lt_to_str(Node_Configuration_Names[j][0]),
       
   734                                         a3=Node_Configuration_Names[j][1])
       
   735                     self.FatalError(error_message)
   688 
   736 
   689         # Search for use of duplicate port numbers by Modbus/IP servers
   737         # Search for use of duplicate port numbers by Modbus/IP servers
   690         # print IPServer_port_numbers
   738         # Note: We only consider duplicate port numbers if using the same network interface!
   691         # ..but first define a lambda function to convert a tuple with the config tree location to a nice looking string
   739         i = 0
   692         #   for e.g., convert the tuple (0, 3, 4) to "0.3.4"
   740         for loc1, addr1, port1 in IPServer_port_numbers[:-1]:
   693 
   741             i = i + 1
   694         for i in range(0, len(IPServer_port_numbers) - 1):
   742             for loc2, addr2, port2 in IPServer_port_numbers[i:]:
   695             for j in range(i + 1, len(IPServer_port_numbers)):
   743                 if (port1 == port2) and (
   696                 if IPServer_port_numbers[i][1] == IPServer_port_numbers[j][1]:
   744                           (addr1 == addr2)   # on the same network interface
   697                     error_message = _("Error: Modbus/IP Servers %{a1}.x and %{a2}.x use the same port number {a3}.\n").format(
   745                        or (addr1 == "") or (addr1 == "*") or (addr1 == "#ANY#") # or one (or both) of the servers
   698                                         a1=_lt_to_str(IPServer_port_numbers[i][0]),
   746                        or (addr2 == "") or (addr2 == "*") or (addr2 == "#ANY#") # use all available network interfaces
   699                                         a2=_lt_to_str(IPServer_port_numbers[j][0]),
   747                    ):
   700                                         a3=IPServer_port_numbers[j][1])
   748                     error_message = _("Error: Modbus plugin nodes %{a1}.x and %{a2}.x use same port number \"{a3}\" " + 
       
   749                                       "on the same (or overlapping) network interfaces \"{a4}\" and \"{a5}\".\n").format(
       
   750                                         a1=_lt_to_str(loc1), a2=_lt_to_str(loc2), a3=port1, a4=addr1, a5=addr2)
   701                     self.FatalError(error_message)
   751                     self.FatalError(error_message)
   702                     #self.GetCTRoot().logger.write_warning(error_message)
       
   703                     #raise Exception
       
   704 
   752 
   705         # Determine the current location in Beremiz's project configuration
   753         # Determine the current location in Beremiz's project configuration
   706         # tree
   754         # tree
   707         current_location = self.GetCurrentLocation()
   755         current_location = self.GetCurrentLocation()
   708 
   756