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 \ |
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 |
411 def GetIPServerPortNumbers(self): |
415 def GetIPServerPortNumbers(self): |
412 port = self.GetParamsAttributes()[0]["children"][1]["value"] |
416 port = self.GetParamsAttributes()[0]["children"][1]["value"] |
413 return [(self.GetCurrentLocation(), port)] |
417 return [(self.GetCurrentLocation(), port)] |
|
418 |
|
419 def GetConfigName(self): |
|
420 """ Return the node's Configuration_Name """ |
|
421 return self.ModbusServerNode.getConfiguration_Name() |
414 |
422 |
415 def CTNGenerate_C(self, buildpath, locations): |
423 def CTNGenerate_C(self, buildpath, locations): |
416 """ |
424 """ |
417 Generate C code |
425 Generate C code |
418 @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) |
426 @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 |
505 # Return the number of (modbus library) nodes this specific RTU client will need |
498 # return type: (tcp nodes, rtu nodes, ascii nodes) |
506 # return type: (tcp nodes, rtu nodes, ascii nodes) |
499 def GetNodeCount(self): |
507 def GetNodeCount(self): |
500 return (0, 1, 0) |
508 return (0, 1, 0) |
501 |
509 |
|
510 def GetConfigName(self): |
|
511 """ Return the node's Configuration_Name """ |
|
512 return self.ModbusRTUclient.getConfiguration_Name() |
|
513 |
502 def CTNGenerate_C(self, buildpath, locations): |
514 def CTNGenerate_C(self, buildpath, locations): |
503 """ |
515 """ |
504 Generate C code |
516 Generate C code |
505 @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) |
517 @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) |
506 @param locations: List of complete variables locations \ |
518 @param locations: List of complete variables locations \ |
583 # Return the number of (modbus library) nodes this specific RTU slave will need |
595 # Return the number of (modbus library) nodes this specific RTU slave will need |
584 # return type: (tcp nodes, rtu nodes, ascii nodes) |
596 # return type: (tcp nodes, rtu nodes, ascii nodes) |
585 def GetNodeCount(self): |
597 def GetNodeCount(self): |
586 return (0, 1, 0) |
598 return (0, 1, 0) |
587 |
599 |
|
600 def GetConfigName(self): |
|
601 """ Return the node's Configuration_Name """ |
|
602 return self.ModbusRTUslave.getConfiguration_Name() |
|
603 |
588 def CTNGenerate_C(self, buildpath, locations): |
604 def CTNGenerate_C(self, buildpath, locations): |
589 """ |
605 """ |
590 Generate C code |
606 Generate C code |
591 @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) |
607 @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) |
592 @param locations: List of complete variables locations \ |
608 @param locations: List of complete variables locations \ |
644 # ask each child how many nodes it needs, and add them all up. |
660 # ask each child how many nodes it needs, and add them all up. |
645 total_node_count = tuple( |
661 total_node_count = tuple( |
646 x1 + x2 for x1, x2 in zip(total_node_count, child.GetNodeCount())) |
662 x1 + x2 for x1, x2 in zip(total_node_count, child.GetNodeCount())) |
647 return total_node_count |
663 return total_node_count |
648 |
664 |
649 # Return a list with tuples of the (location, port numbers) used by all |
665 # 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): |
666 def GetIPServerPortNumbers(self): |
652 IPServer_port_numbers = [] |
667 IPServer_port_numbers = [] |
653 for child in self.IECSortedChildren(): |
668 for child in self.IECSortedChildren(): |
654 if child.CTNType == "ModbusTCPserver": |
669 if child.CTNType == "ModbusTCPserver": |
655 IPServer_port_numbers.extend(child.GetIPServerPortNumbers()) |
670 IPServer_port_numbers.extend(child.GetIPServerPortNumbers()) |
656 return IPServer_port_numbers |
671 return IPServer_port_numbers |
|
672 |
|
673 # Return a list with tuples of the (location, configuration_name) used by all the Modbus nodes (tcp/rtu, clients/servers) |
|
674 def GetConfigNames(self): |
|
675 Node_Configuration_Names = [] |
|
676 for child in self.IECSortedChildren(): |
|
677 Node_Configuration_Names.extend([(child.GetCurrentLocation(), child.GetConfigName())]) |
|
678 return Node_Configuration_Names |
657 |
679 |
658 def CTNGenerate_C(self, buildpath, locations): |
680 def CTNGenerate_C(self, buildpath, locations): |
659 # print "#############" |
681 # print "#############" |
660 # print self.__class__ |
682 # print self.__class__ |
661 # print type(self) |
683 # print type(self) |
671 # total_node_count: (tcp nodes, rtu nodes, ascii nodes) |
693 # 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 |
694 # Also get a list with tuples of (location, IP port numbers) used by all the Modbus/IP server nodes |
673 # This list is later used to search for duplicates in port numbers! |
695 # This list is later used to search for duplicates in port numbers! |
674 # IPServer_port_numbers = [(location ,IPserver_port_number), ...] |
696 # IPServer_port_numbers = [(location ,IPserver_port_number), ...] |
675 # location: tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x" |
697 # 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 |
698 # IPserver_port_number: a number (i.e. port number used by the Modbus/IP server) |
677 # Modbus/IP server) |
699 # Also get a list with tuples of (location, Configuration_Name) used by all the Modbus nodes |
|
700 # This list is later used to search for duplicates in Configuration Names! |
|
701 # Node_Configuration_Names = [(location, Configuration_Name), ...] |
|
702 # location: tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x" |
|
703 # Configuration_Name: the "Configuration_Name" string |
678 total_node_count = (0, 0, 0) |
704 total_node_count = (0, 0, 0) |
679 IPServer_port_numbers = [] |
705 IPServer_port_numbers = [] |
|
706 Node_Configuration_Names = [] |
680 for CTNInstance in self.GetCTRoot().IterChildren(): |
707 for CTNInstance in self.GetCTRoot().IterChildren(): |
681 if CTNInstance.CTNType == "modbus": |
708 if CTNInstance.CTNType == "modbus": |
682 # ask each modbus plugin instance how many nodes it needs, and |
709 # ask each modbus plugin instance how many nodes it needs, and add them all up. |
683 # add them all up. |
710 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( |
711 IPServer_port_numbers. extend(CTNInstance.GetIPServerPortNumbers()) |
685 total_node_count, CTNInstance.GetNodeCount())) |
712 Node_Configuration_Names.extend(CTNInstance.GetConfigNames ()) |
686 IPServer_port_numbers.extend( |
713 |
687 CTNInstance.GetIPServerPortNumbers()) |
714 # Search for use of duplicate Configuration_Names by Modbus nodes |
|
715 # Configuration Names are used by the web server running on the PLC |
|
716 # (more precisely, run by Beremiz_service.py) to identify and allow |
|
717 # changing the Modbus parameters after the program has been downloaded |
|
718 # to the PLC (but before it is started) |
|
719 # With clashes in the configuration names, the Modbus nodes will not be |
|
720 # distinguasheble on the web interface! |
|
721 for i in range(0, len(Node_Configuration_Names) - 1): |
|
722 for j in range(i + 1, len(Node_Configuration_Names)): |
|
723 if Node_Configuration_Names[i][1] == Node_Configuration_Names[j][1]: |
|
724 error_message = _("Error: Modbus plugin nodes %{a1}.x and %{a2}.x use the same Configuration_Name \"{a3}\".\n").format( |
|
725 a1=_lt_to_str(Node_Configuration_Names[i][0]), |
|
726 a2=_lt_to_str(Node_Configuration_Names[j][0]), |
|
727 a3=Node_Configuration_Names[j][1]) |
|
728 self.FatalError(error_message) |
688 |
729 |
689 # Search for use of duplicate port numbers by Modbus/IP servers |
730 # Search for use of duplicate port numbers by Modbus/IP servers |
690 # print IPServer_port_numbers |
731 # print IPServer_port_numbers |
691 # ..but first define a lambda function to convert a tuple with the config tree location to a nice looking string |
732 # ..but first define a lambda function to convert a tuple with the config tree location to a nice looking string |
692 # for e.g., convert the tuple (0, 3, 4) to "0.3.4" |
733 # for e.g., convert the tuple (0, 3, 4) to "0.3.4" |
693 |
|
694 for i in range(0, len(IPServer_port_numbers) - 1): |
734 for i in range(0, len(IPServer_port_numbers) - 1): |
695 for j in range(i + 1, len(IPServer_port_numbers)): |
735 for j in range(i + 1, len(IPServer_port_numbers)): |
696 if IPServer_port_numbers[i][1] == IPServer_port_numbers[j][1]: |
736 if IPServer_port_numbers[i][1] == IPServer_port_numbers[j][1]: |
697 error_message = _("Error: Modbus/IP Servers %{a1}.x and %{a2}.x use the same port number {a3}.\n").format( |
737 error_message = _("Error: Modbus/IP Servers %{a1}.x and %{a2}.x use the same port number {a3}.\n").format( |
698 a1=_lt_to_str(IPServer_port_numbers[i][0]), |
738 a1=_lt_to_str(IPServer_port_numbers[i][0]), |
699 a2=_lt_to_str(IPServer_port_numbers[j][0]), |
739 a2=_lt_to_str(IPServer_port_numbers[j][0]), |
700 a3=IPServer_port_numbers[j][1]) |
740 a3=IPServer_port_numbers[j][1]) |
701 self.FatalError(error_message) |
741 self.FatalError(error_message) |
702 #self.GetCTRoot().logger.write_warning(error_message) |
|
703 #raise Exception |
|
704 |
742 |
705 # Determine the current location in Beremiz's project configuration |
743 # Determine the current location in Beremiz's project configuration |
706 # tree |
744 # tree |
707 current_location = self.GetCurrentLocation() |
745 current_location = self.GetCurrentLocation() |
708 |
746 |