msousa@1909: #!/usr/bin/env python msousa@1909: # -*- coding: utf-8 -*- msousa@1909: msousa@1909: # This file is part of Beremiz, a Integrated Development Environment for msousa@1909: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. msousa@1909: # msousa@1909: # Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt) msousa@1909: # msousa@1909: # This program is free software: you can redistribute it and/or modify msousa@1909: # it under the terms of the GNU General Public License as published by msousa@1909: # the Free Software Foundation, either version 3 of the License, or msousa@1909: # (at your option) any later version. msousa@1909: # msousa@1909: # This program is distributed in the hope that it will be useful, msousa@1909: # but WITHOUT ANY WARRANTY; without even the implied warranty of msousa@1909: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the msousa@1909: # GNU General Public License for more details. msousa@1909: # msousa@1909: # You should have received a copy of the GNU General Public License msousa@1909: # along with this program. If not, see . msousa@1909: # msousa@1909: # This code is made available on the understanding that it will not be msousa@1909: # used in safety-critical situations without a full and competent review. msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: import os, sys msousa@1909: base_folder = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] msousa@1909: base_folder = os.path.join(base_folder, "..") msousa@1909: ModbusPath = os.path.join(base_folder, "Modbus") msousa@1909: msousa@1909: from mb_utils import * msousa@1909: msousa@1909: import wx msousa@1909: from ConfigTreeNode import ConfigTreeNode msousa@1909: from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY msousa@1909: msousa@1909: msousa@1909: msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: # # msousa@1909: # C L I E N T R E Q U E S T # msousa@1909: # # msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: msousa@1909: msousa@1909: class _RequestPlug: msousa@1909: XSD = """ msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: """ msousa@1909: msousa@1909: def GetParamsAttributes(self, path = None): msousa@1909: infos = ConfigTreeNode.GetParamsAttributes(self, path = path) msousa@1909: for element in infos: msousa@1909: if element["name"] == "ModbusRequest": msousa@1909: for child in element["children"]: msousa@1909: if child["name"] == "Function": msousa@1909: list = modbus_function_dict.keys() msousa@1909: list.sort() msousa@1909: child["type"] = list msousa@1909: return infos msousa@1909: msousa@1909: def GetVariableLocationTree(self): msousa@1909: current_location = self.GetCurrentLocation() msousa@1909: name = self.BaseParams.getName() msousa@1909: address = self.GetParamsAttributes()[0]["children"][3]["value"] msousa@1909: count = self.GetParamsAttributes()[0]["children"][2]["value"] msousa@1909: function= self.GetParamsAttributes()[0]["children"][0]["value"] msousa@1909: # 'BOOL' or 'WORD' msousa@1909: datatype= modbus_function_dict[function][3] msousa@1909: # 1 or 16 msousa@1909: datasize= modbus_function_dict[function][4] msousa@1909: # 'Q' for coils and holding registers, 'I' for input discretes and input registers msousa@1909: datazone= modbus_function_dict[function][5] msousa@1909: # 'X' for bits, 'W' for words msousa@1909: datatacc= modbus_function_dict[function][6] msousa@1909: # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register' msousa@1909: dataname= modbus_function_dict[function][7] msousa@1909: entries = [] msousa@1909: for offset in range(address, address+count): msousa@1909: entries.append({ msousa@1909: "name": dataname + " " + str(offset), msousa@1909: "type": LOCATION_VAR_MEMORY, msousa@1909: "size": datasize, msousa@1909: "IEC_type": datatype, msousa@1909: "var_name": "var_name", msousa@1909: "location": datatacc + ".".join([str(i) for i in current_location]) + "." + str(offset), msousa@1909: "description": "description", msousa@1909: "children": []}) msousa@1909: return {"name": name, msousa@1909: "type": LOCATION_CONFNODE, msousa@1909: "location": ".".join([str(i) for i in current_location]) + ".x", msousa@1909: "children": entries} msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: def CTNGenerate_C(self, buildpath, locations): msousa@1909: """ msousa@1909: Generate C code msousa@1909: @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) msousa@1909: @param locations: List of complete variables locations \ msousa@1909: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) msousa@1909: "NAME" : name of the variable (generally "__IW0_1_2" style) msousa@1909: "DIR" : direction "Q","I" or "M" msousa@1909: "SIZE" : size "X", "B", "W", "D", "L" msousa@1909: "LOC" : tuple of interger for IEC location (0,1,2,...) msousa@1909: }, ...] msousa@1909: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND msousa@1909: """ msousa@1909: return [], "", False msousa@1909: msousa@1909: msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: # # msousa@1909: # S E R V E R M E M O R Y A R E A # msousa@1909: # # msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: msousa@1909: #dictionary implementing: msousa@1909: #key - string with the description we want in the request plugin GUI msousa@1909: #list - (modbus function number, request type, max count value) msousa@1909: modbus_memtype_dict = {"01 - Coils" : ( '1', 'rw_bits', 65536, "BOOL", 1 , "Q", "X", "Coil"), msousa@1909: "02 - Input Discretes" : ( '2', 'ro_bits', 65536, "BOOL", 1 , "I", "X", "Input Discrete"), msousa@1909: "03 - Holding Registers" :( '3', 'rw_words', 65536, "WORD", 16 , "Q", "W", "Holding Register"), msousa@1909: "04 - Input Registers" : ( '4', 'ro_words', 65536, "WORD", 16 , "I", "W", "Input Register"), msousa@1909: } msousa@1909: msousa@1909: class _MemoryAreaPlug: msousa@1909: XSD = """ msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: """ msousa@1909: msousa@1909: def GetParamsAttributes(self, path = None): msousa@1909: infos = ConfigTreeNode.GetParamsAttributes(self, path = path) msousa@1909: for element in infos: msousa@1909: if element["name"] == "MemoryArea": msousa@1909: for child in element["children"]: msousa@1909: if child["name"] == "MemoryAreaType": msousa@1909: list = modbus_memtype_dict.keys() msousa@1909: list.sort() msousa@1909: child["type"] = list msousa@1909: return infos msousa@1909: msousa@1909: def GetVariableLocationTree(self): msousa@1909: current_location = self.GetCurrentLocation() msousa@1909: name = self.BaseParams.getName() msousa@1909: address = self.GetParamsAttributes()[0]["children"][2]["value"] msousa@1909: count = self.GetParamsAttributes()[0]["children"][1]["value"] msousa@1909: function= self.GetParamsAttributes()[0]["children"][0]["value"] msousa@1909: # 'BOOL' or 'WORD' msousa@1909: datatype= modbus_memtype_dict[function][3] msousa@1909: # 1 or 16 msousa@1909: datasize= modbus_memtype_dict[function][4] msousa@1909: # 'Q' for coils and holding registers, 'I' for input discretes and input registers msousa@1909: datazone= modbus_memtype_dict[function][5] msousa@1909: # 'X' for bits, 'W' for words msousa@1909: datatacc= modbus_memtype_dict[function][6] msousa@1909: # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register' msousa@1909: dataname= modbus_memtype_dict[function][7] msousa@1909: entries = [] msousa@1909: for offset in range(address, address+count): msousa@1909: entries.append({ msousa@1909: "name": dataname + " " + str(offset), msousa@1909: "type": LOCATION_VAR_MEMORY, msousa@1909: "size": datasize, msousa@1909: "IEC_type": datatype, msousa@1909: "var_name": "var_name", msousa@1909: "location": datatacc + ".".join([str(i) for i in current_location]) + "." + str(offset), msousa@1909: "description": "description", msousa@1909: "children": []}) msousa@1909: return {"name": name, msousa@1909: "type": LOCATION_CONFNODE, msousa@1909: "location": ".".join([str(i) for i in current_location]) + ".x", msousa@1909: "children": entries} msousa@1909: msousa@1909: def CTNGenerate_C(self, buildpath, locations): msousa@1909: """ msousa@1909: Generate C code msousa@1909: @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) msousa@1909: @param locations: List of complete variables locations \ msousa@1909: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) msousa@1909: "NAME" : name of the variable (generally "__IW0_1_2" style) msousa@1909: "DIR" : direction "Q","I" or "M" msousa@1909: "SIZE" : size "X", "B", "W", "D", "L" msousa@1909: "LOC" : tuple of interger for IEC location (0,1,2,...) msousa@1909: }, ...] msousa@1909: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND msousa@1909: """ msousa@1909: return [], "", False msousa@1909: msousa@1909: msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: # # msousa@1909: # T C P C L I E N T # msousa@1909: # # msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: msousa@1909: class _ModbusTCPclientPlug: msousa@1909: XSD = """ msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: """ msousa@1909: # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms corresponds to aprox 25 days. msousa@1909: CTNChildrenTypes = [("ModbusRequest",_RequestPlug, "Request")] msousa@1909: # TODO: Replace with CTNType !!! msousa@1909: PlugType = "ModbusTCPclient" msousa@1909: msousa@1909: # Return the number of (modbus library) nodes this specific TCP client will need msousa@1909: # return type: (tcp nodes, rtu nodes, ascii nodes) msousa@1909: def GetNodeCount(self): msousa@1909: return (1, 0, 0) msousa@1909: msousa@1909: def CTNGenerate_C(self, buildpath, locations): msousa@1909: """ msousa@1909: Generate C code msousa@1909: @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) msousa@1909: @param locations: List of complete variables locations \ msousa@1909: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) msousa@1909: "NAME" : name of the variable (generally "__IW0_1_2" style) msousa@1909: "DIR" : direction "Q","I" or "M" msousa@1909: "SIZE" : size "X", "B", "W", "D", "L" msousa@1909: "LOC" : tuple of interger for IEC location (0,1,2,...) msousa@1909: }, ...] msousa@1909: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND msousa@1909: """ msousa@1909: return [], "", False msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: # # msousa@1909: # T C P S E R V E R # msousa@1909: # # msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: msousa@1909: class _ModbusTCPserverPlug: msousa@1909: # NOTE: the Port number is a 'string' and not an 'integer'! msousa@1909: # This is because the underlying modbus library accepts strings msousa@1909: # (e.g.: well known port names!) msousa@1909: XSD = """ msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: """ msousa@1909: CTNChildrenTypes = [("MemoryArea",_MemoryAreaPlug, "Memory Area")] msousa@1909: # TODO: Replace with CTNType !!! msousa@1909: PlugType = "ModbusTCPserver" msousa@1909: msousa@1909: # Return the number of (modbus library) nodes this specific TCP server will need msousa@1909: # return type: (tcp nodes, rtu nodes, ascii nodes) msousa@1909: def GetNodeCount(self): msousa@1909: return (1, 0, 0) msousa@1909: msousa@1909: # Return a list with a single tuple conatining the (location, port number) msousa@1909: # location: location of this node in the configuration tree msousa@1909: # port number: IP port used by this Modbus/IP server msousa@1909: def GetIPServerPortNumbers(self): msousa@1909: port = self.GetParamsAttributes()[0]["children"][1]["value"] msousa@1909: return [(self.GetCurrentLocation() , port)] msousa@1909: msousa@1909: def CTNGenerate_C(self, buildpath, locations): msousa@1909: """ msousa@1909: Generate C code msousa@1909: @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) msousa@1909: @param locations: List of complete variables locations \ msousa@1909: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) msousa@1909: "NAME" : name of the variable (generally "__IW0_1_2" style) msousa@1909: "DIR" : direction "Q","I" or "M" msousa@1909: "SIZE" : size "X", "B", "W", "D", "L" msousa@1909: "LOC" : tuple of interger for IEC location (0,1,2,...) msousa@1909: }, ...] msousa@1909: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND msousa@1909: """ msousa@1909: return [], "", False msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: # # msousa@1909: # R T U C L I E N T # msousa@1909: # # msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: msousa@1909: class _ModbusRTUclientPlug: msousa@1909: XSD = """ msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: """ msousa@1909: # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms corresponds to aprox 25 days. msousa@1909: CTNChildrenTypes = [("ModbusRequest",_RequestPlug, "Request")] msousa@1909: # TODO: Replace with CTNType !!! msousa@1909: PlugType = "ModbusRTUclient" msousa@1909: msousa@1909: def GetParamsAttributes(self, path = None): msousa@1909: infos = ConfigTreeNode.GetParamsAttributes(self, path = path) msousa@1909: for element in infos: msousa@1909: if element["name"] == "ModbusRTUclient": msousa@1909: for child in element["children"]: msousa@1909: if child["name"] == "Baud_Rate": msousa@1909: child["type"] = modbus_serial_baudrate_list msousa@1909: if child["name"] == "Stop_Bits": msousa@1909: child["type"] = modbus_serial_stopbits_list msousa@1909: if child["name"] == "Parity": msousa@1909: child["type"] = modbus_serial_parity_dict.keys() msousa@1909: return infos msousa@1909: msousa@1909: # Return the number of (modbus library) nodes this specific RTU client will need msousa@1909: # return type: (tcp nodes, rtu nodes, ascii nodes) msousa@1909: def GetNodeCount(self): msousa@1909: return (0, 1, 0) msousa@1909: msousa@1909: def CTNGenerate_C(self, buildpath, locations): msousa@1909: """ msousa@1909: Generate C code msousa@1909: @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) msousa@1909: @param locations: List of complete variables locations \ msousa@1909: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) msousa@1909: "NAME" : name of the variable (generally "__IW0_1_2" style) msousa@1909: "DIR" : direction "Q","I" or "M" msousa@1909: "SIZE" : size "X", "B", "W", "D", "L" msousa@1909: "LOC" : tuple of interger for IEC location (0,1,2,...) msousa@1909: }, ...] msousa@1909: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND msousa@1909: """ msousa@1909: return [], "", False msousa@1909: msousa@1909: msousa@1909: msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: # # msousa@1909: # R T U S L A V E # msousa@1909: # # msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: msousa@1909: msousa@1909: class _ModbusRTUslavePlug: msousa@1909: XSD = """ msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: """ msousa@1909: CTNChildrenTypes = [("MemoryArea",_MemoryAreaPlug, "Memory Area")] msousa@1909: # TODO: Replace with CTNType !!! msousa@1909: PlugType = "ModbusRTUslave" msousa@1909: msousa@1909: def GetParamsAttributes(self, path = None): msousa@1909: infos = ConfigTreeNode.GetParamsAttributes(self, path = path) msousa@1909: for element in infos: msousa@1909: if element["name"] == "ModbusRTUslave": msousa@1909: for child in element["children"]: msousa@1909: if child["name"] == "Baud_Rate": msousa@1909: child["type"] = modbus_serial_baudrate_list msousa@1909: if child["name"] == "Stop_Bits": msousa@1909: child["type"] = modbus_serial_stopbits_list msousa@1909: if child["name"] == "Parity": msousa@1909: child["type"] = modbus_serial_parity_dict.keys() msousa@1909: return infos msousa@1909: msousa@1909: # Return the number of (modbus library) nodes this specific RTU slave will need msousa@1909: # return type: (tcp nodes, rtu nodes, ascii nodes) msousa@1909: def GetNodeCount(self): msousa@1909: return (0, 1, 0) msousa@1909: msousa@1909: def CTNGenerate_C(self, buildpath, locations): msousa@1909: """ msousa@1909: Generate C code msousa@1909: @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) msousa@1909: @param locations: List of complete variables locations \ msousa@1909: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) msousa@1909: "NAME" : name of the variable (generally "__IW0_1_2" style) msousa@1909: "DIR" : direction "Q","I" or "M" msousa@1909: "SIZE" : size "X", "B", "W", "D", "L" msousa@1909: "LOC" : tuple of interger for IEC location (0,1,2,...) msousa@1909: }, ...] msousa@1909: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND msousa@1909: """ msousa@1909: return [], "", False msousa@1909: msousa@1909: msousa@1909: msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: # # msousa@1909: # R O O T C L A S S # msousa@1909: # # msousa@1909: ################################################### msousa@1909: ################################################### msousa@1909: class RootClass: msousa@1909: XSD = """ msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: """ msousa@1909: CTNChildrenTypes = [("ModbusTCPclient",_ModbusTCPclientPlug, "Modbus TCP Client") msousa@1909: ,("ModbusTCPserver",_ModbusTCPserverPlug, "Modbus TCP Server") msousa@1909: ,("ModbusRTUclient",_ModbusRTUclientPlug, "Modbus RTU Client") msousa@1909: ,("ModbusRTUslave", _ModbusRTUslavePlug, "Modbus RTU Slave") msousa@1909: ] msousa@1909: msousa@1909: # Return the number of (modbus library) nodes this specific instance of the modbus plugin will need msousa@1909: # return type: (tcp nodes, rtu nodes, ascii nodes) msousa@1909: def GetNodeCount(self): msousa@1909: max_remote_tcpclient = self.GetParamsAttributes()[0]["children"][0]["value"] msousa@1909: total_node_count = (max_remote_tcpclient, 0, 0) msousa@1909: for child in self.IECSortedChildren(): msousa@1909: # ask each child how many nodes it needs, and add them all up. msousa@1909: total_node_count = tuple(x1 + x2 for x1, x2 in zip(total_node_count, child.GetNodeCount())) msousa@1909: return total_node_count msousa@1909: msousa@1909: # Return a list with tuples of the (location, port numbers) used by all the Modbus/IP servers msousa@1909: def GetIPServerPortNumbers(self): msousa@1909: IPServer_port_numbers = [] msousa@1909: for child in self.IECSortedChildren(): msousa@1909: if child.CTNType == "ModbusTCPserver": msousa@1909: IPServer_port_numbers.extend(child.GetIPServerPortNumbers()) msousa@1909: return IPServer_port_numbers msousa@1909: msousa@1909: def CTNGenerate_C(self, buildpath, locations): msousa@1909: #print "#############" msousa@1909: #print self.__class__ msousa@1909: #print type(self) msousa@1909: #print "self.CTNType >>>" msousa@1909: #print self.CTNType msousa@1909: #print "type(self.CTNType) >>>" msousa@1909: #print type(self.CTNType) msousa@1909: #print "#############" msousa@1909: msousa@1909: loc_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())), msousa@1909: } msousa@1909: msousa@1909: # Determine the number of (modbus library) nodes ALL instances of the modbus plugin will need msousa@1909: # total_node_count: (tcp nodes, rtu nodes, ascii nodes) msousa@1909: # Also get a list with tuples of (location, IP port numbers) used by all the Modbus/IP server nodes msousa@1909: # This list is later used to search for duplicates in port numbers! msousa@1909: # IPServer_port_numbers = [(location ,IPserver_port_number), ...] msousa@1909: # location: tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x" msousa@1909: # IPserver_port_number: a number (i.e. port number used by the Modbus/IP server) msousa@1909: total_node_count = (0, 0, 0) msousa@1909: IPServer_port_numbers = [] msousa@1909: for CTNInstance in self.GetCTRoot().IterChildren(): msousa@1909: if CTNInstance.CTNType == "modbus": msousa@1909: # ask each modbus plugin instance how many nodes it needs, and add them all up. msousa@1909: total_node_count = tuple(x1 + x2 for x1, x2 in zip(total_node_count, CTNInstance.GetNodeCount())) msousa@1909: IPServer_port_numbers.extend(CTNInstance.GetIPServerPortNumbers()) msousa@1909: msousa@1909: # Search for use of duplicate port numbers by Modbus/IP servers msousa@1909: #print IPServer_port_numbers msousa@1909: # ..but first define a lambda function to convert a tuple with the config tree location to a nice looking string msousa@1909: # for e.g., convert the tuple (0, 3, 4) to "0.3.4" msousa@1909: lt_to_str = lambda loctuple: '.'.join(map(str, loctuple)) msousa@1909: for i in range(0, len(IPServer_port_numbers)-1): msousa@1909: for j in range (i+1, len(IPServer_port_numbers)): msousa@1909: if IPServer_port_numbers[i][1] == IPServer_port_numbers[j][1]: msousa@1909: self.GetCTRoot().logger.write_warning(_("Error: Modbus/IP Servers %s.x and %s.x use the same port number %s.\n")%(lt_to_str(IPServer_port_numbers[i][0]), lt_to_str(IPServer_port_numbers[j][0]), IPServer_port_numbers[j][1])) msousa@1909: raise Exception, False msousa@1909: # TODO: return an error code instead of raising an exception msousa@1909: msousa@1909: # Determine the current location in Beremiz's project configuration tree msousa@1909: current_location = self.GetCurrentLocation() msousa@1909: msousa@1909: # define a unique name for the generated C and h files msousa@1909: prefix = "_".join(map(str, current_location)) msousa@1909: Gen_MB_c_path = os.path.join(buildpath, "MB_%s.c"%prefix) msousa@1909: Gen_MB_h_path = os.path.join(buildpath, "MB_%s.h"%prefix) msousa@1909: c_filename = os.path.join(os.path.split(__file__)[0],"mb_runtime.c") msousa@1909: h_filename = os.path.join(os.path.split(__file__)[0],"mb_runtime.h") msousa@1909: msousa@1909: tcpclient_reqs_count = 0 msousa@1909: rtuclient_reqs_count = 0 msousa@1909: ascclient_reqs_count = 0 msousa@1909: tcpclient_node_count = 0 msousa@1909: rtuclient_node_count = 0 msousa@1909: ascclient_node_count = 0 msousa@1909: tcpserver_node_count = 0 msousa@1909: rtuserver_node_count = 0 msousa@1909: ascserver_node_count = 0 msousa@1909: nodeid = 0 msousa@1909: client_nodeid = 0 msousa@1909: client_requestid = 0 msousa@1909: server_id = 0 msousa@1909: msousa@1909: server_node_list = [] msousa@1909: client_node_list = [] msousa@1909: client_request_list = [] msousa@1909: server_memarea_list = [] msousa@1909: loc_vars = [] msousa@1909: loc_vars_list = [] # list of variables already declared in C code! msousa@1909: for child in self.IECSortedChildren(): msousa@1909: #print "<<<<<<<<<<<<<" msousa@1909: #print "child (self.IECSortedChildren())----->" msousa@1909: #print child.__class__ msousa@1909: #print ">>>>>>>>>>>>>" msousa@1909: ###################################### msousa@1909: if child.PlugType == "ModbusTCPserver": msousa@1909: tcpserver_node_count += 1 msousa@1909: new_node = GetTCPServerNodePrinted(self, child) msousa@1909: if new_node is None: msousa@1909: return [],"",False msousa@1909: server_node_list.append(new_node) msousa@1909: ############## msousa@1909: for subchild in child.IECSortedChildren(): msousa@1909: new_memarea = GetTCPServerMemAreaPrinted(self, subchild, nodeid) msousa@1909: if new_memarea is None: msousa@1909: return [],"",False msousa@1909: server_memarea_list.append(new_memarea) msousa@1909: function= subchild.GetParamsAttributes()[0]["children"][0]["value"] msousa@1909: # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words' msousa@1909: memarea= modbus_memtype_dict[function][1] msousa@1909: for iecvar in subchild.GetLocations(): msousa@1909: #print repr(iecvar) msousa@1909: absloute_address = iecvar["LOC"][3] msousa@1909: start_address = int(subchild.GetParamsAttributes()[0]["children"][2]["value"]) msousa@1909: relative_addr = absloute_address - start_address msousa@1909: #test if relative address in request specified range msousa@1909: if relative_addr in xrange(int(subchild.GetParamsAttributes()[0]["children"][1]["value"])): msousa@1909: if str(iecvar["NAME"]) not in loc_vars_list: msousa@1909: loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (server_id, memarea, absloute_address)) msousa@1909: loc_vars_list.append(str(iecvar["NAME"])) msousa@1909: server_id += 1 msousa@1909: ###################################### msousa@1909: if child.PlugType == "ModbusRTUslave": msousa@1909: rtuserver_node_count += 1 msousa@1909: new_node = GetRTUSlaveNodePrinted(self, child) msousa@1909: if new_node is None: msousa@1909: return [],"",False msousa@1909: server_node_list.append(new_node) msousa@1909: ############## msousa@1909: for subchild in child.IECSortedChildren(): msousa@1909: new_memarea = GetTCPServerMemAreaPrinted(self, subchild, nodeid) msousa@1909: if new_memarea is None: msousa@1909: return [],"",False msousa@1909: server_memarea_list.append(new_memarea) msousa@1909: function= subchild.GetParamsAttributes()[0]["children"][0]["value"] msousa@1909: # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words' msousa@1909: memarea= modbus_memtype_dict[function][1] msousa@1909: for iecvar in subchild.GetLocations(): msousa@1909: #print repr(iecvar) msousa@1909: absloute_address = iecvar["LOC"][3] msousa@1909: start_address = int(subchild.GetParamsAttributes()[0]["children"][2]["value"]) msousa@1909: relative_addr = absloute_address - start_address msousa@1909: #test if relative address in request specified range msousa@1909: if relative_addr in xrange(int(subchild.GetParamsAttributes()[0]["children"][1]["value"])): msousa@1909: if str(iecvar["NAME"]) not in loc_vars_list: msousa@1909: loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (server_id, memarea, absloute_address)) msousa@1909: loc_vars_list.append(str(iecvar["NAME"])) msousa@1909: server_id += 1 msousa@1909: ###################################### msousa@1909: if child.PlugType == "ModbusTCPclient": msousa@1909: tcpclient_reqs_count += len(child.IECSortedChildren()) msousa@1909: new_node = GetTCPClientNodePrinted(self, child) msousa@1909: if new_node is None: msousa@1909: return [],"",False msousa@1909: client_node_list.append(new_node) msousa@1909: for subchild in child.IECSortedChildren(): msousa@1909: new_req = GetClientRequestPrinted(self, subchild, client_nodeid) msousa@1909: if new_req is None: msousa@1909: return [],"",False msousa@1909: client_request_list.append(new_req) msousa@1909: for iecvar in subchild.GetLocations(): msousa@1909: #absloute address - start address msousa@1909: relative_addr = iecvar["LOC"][3] - int(subchild.GetParamsAttributes()[0]["children"][3]["value"]) msousa@1909: #test if relative address in request specified range msousa@1909: if relative_addr in xrange(int(subchild.GetParamsAttributes()[0]["children"][2]["value"])): msousa@1909: if str(iecvar["NAME"]) not in loc_vars_list: msousa@1909: loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr)) msousa@1909: loc_vars_list.append(str(iecvar["NAME"])) msousa@1909: client_requestid += 1 msousa@1909: tcpclient_node_count += 1 msousa@1909: client_nodeid += 1 msousa@1909: ###################################### msousa@1909: if child.PlugType == "ModbusRTUclient": msousa@1909: rtuclient_reqs_count += len(child.IECSortedChildren()) msousa@1909: new_node = GetRTUClientNodePrinted(self, child) msousa@1909: if new_node is None: msousa@1909: return [],"",False msousa@1909: client_node_list.append(new_node) msousa@1909: for subchild in child.IECSortedChildren(): msousa@1909: new_req = GetClientRequestPrinted(self, subchild, client_nodeid) msousa@1909: if new_req is None: msousa@1909: return [],"",False msousa@1909: client_request_list.append(new_req) msousa@1909: for iecvar in subchild.GetLocations(): msousa@1909: #absloute address - start address msousa@1909: relative_addr = iecvar["LOC"][3] - int(subchild.GetParamsAttributes()[0]["children"][3]["value"]) msousa@1909: #test if relative address in request specified range msousa@1909: if relative_addr in xrange(int(subchild.GetParamsAttributes()[0]["children"][2]["value"])): msousa@1909: if str(iecvar["NAME"]) not in loc_vars_list: msousa@1909: loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr)) msousa@1909: loc_vars_list.append(str(iecvar["NAME"])) msousa@1909: client_requestid += 1 msousa@1909: rtuclient_node_count += 1 msousa@1909: client_nodeid += 1 msousa@1909: nodeid += 1 msousa@1909: msousa@1909: loc_dict["loc_vars"] = "\n".join(loc_vars) msousa@1909: loc_dict["server_nodes_params"] = ",\n\n".join(server_node_list) msousa@1909: loc_dict["client_nodes_params"] = ",\n\n".join(client_node_list) msousa@1909: loc_dict["client_req_params"] = ",\n\n".join(client_request_list) msousa@1909: loc_dict["tcpclient_reqs_count"] = str(tcpclient_reqs_count) msousa@1909: loc_dict["tcpclient_node_count"] = str(tcpclient_node_count) msousa@1909: loc_dict["tcpserver_node_count"] = str(tcpserver_node_count) msousa@1909: loc_dict["rtuclient_reqs_count"] = str(rtuclient_reqs_count) msousa@1909: loc_dict["rtuclient_node_count"] = str(rtuclient_node_count) msousa@1909: loc_dict["rtuserver_node_count"] = str(rtuserver_node_count) msousa@1909: loc_dict["ascclient_reqs_count"] = str(ascclient_reqs_count) msousa@1909: loc_dict["ascclient_node_count"] = str(ascclient_node_count) msousa@1909: loc_dict["ascserver_node_count"] = str(ascserver_node_count) msousa@1909: loc_dict["total_tcpnode_count"] = str(total_node_count[0]) msousa@1909: loc_dict["total_rtunode_count"] = str(total_node_count[1]) msousa@1909: loc_dict["total_ascnode_count"] = str(total_node_count[2]) msousa@1909: loc_dict["max_remote_tcpclient"] = int(self.GetParamsAttributes()[0]["children"][0]["value"]) msousa@1909: msousa@1909: #get template file content into a string, format it with dict msousa@1909: #and write it to proper .h file msousa@1909: mb_main = open(h_filename).read() % loc_dict msousa@1909: f = open(Gen_MB_h_path,'w') msousa@1909: f.write(mb_main) msousa@1909: f.close() msousa@1909: #same thing as above, but now to .c file msousa@1909: mb_main = open(c_filename).read() % loc_dict msousa@1909: f = open(Gen_MB_c_path,'w') msousa@1909: f.write(mb_main) msousa@1909: f.close() msousa@1909: msousa@1909: LDFLAGS = [] msousa@1909: LDFLAGS.append(" \"-L" + ModbusPath + "\"") msousa@1909: LDFLAGS.append(" -lmb ") msousa@1909: LDFLAGS.append(" \"-Wl,-rpath," + ModbusPath + "\"") msousa@1909: #LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_slave_and_master.o") + "\"") msousa@1909: #LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_slave.o") + "\"") msousa@1909: #LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_master.o") + "\"") msousa@1909: #LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_tcp.o") + "\"") msousa@1909: #LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_rtu.o") + "\"") msousa@1909: #LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_ascii.o") + "\"") msousa@1909: #LDFLAGS.append("\"" + os.path.join(ModbusPath, "sin_util.o") + "\"") msousa@1909: if os.name == 'nt': # other possible values: 'posix' 'os2' 'ce' 'java' 'riscos' msousa@1909: LDFLAGS.append(" -lws2_32 ") # on windows we need to load winsock library! msousa@1909: msousa@1909: return [(Gen_MB_c_path, ' -I"'+ModbusPath+'"')], LDFLAGS, True