diff -r 000000000000 -r b622defdfd98 PLCControler.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PLCControler.py Wed Jan 31 16:31:39 2007 +0100 @@ -0,0 +1,1827 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C): Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU Lesser General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#Lesser General Public License for more details. +# +#You should have received a copy of the GNU Lesser General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from minixsv import pyxsval +import cPickle +import os,sys,re + +from plcopen import plcopen +from plcopen.structures import * +from graphics.GraphicCommons import * +from PLCGenerator import * + +[ITEM_UNEDITABLE, ITEM_PROJECT, ITEM_POU, ITEM_CLASS, ITEM_VARIABLE, + ITEM_TRANSITION, ITEM_ACTION, ITEM_CONFIGURATION, ITEM_RESOURCE] = range(9) + +#------------------------------------------------------------------------------- +# Undo Buffer for PLCOpenEditor +#------------------------------------------------------------------------------- + +# Length of the buffer +UNDO_BUFFER_LENGTH = 20 + +""" +Class implementing a buffer of changes made on the current editing Object Dictionary +""" +class UndoBuffer: + + # Constructor initialising buffer + def __init__(self, currentstate, issaved = False): + self.Buffer = [] + self.CurrentIndex = -1 + self.MinIndex = -1 + self.MaxIndex = -1 + # if current state is defined + if currentstate: + self.CurrentIndex = 0 + self.MinIndex = 0 + self.MaxIndex = 0 + # Initialising buffer with currentstate at the first place + for i in xrange(UNDO_BUFFER_LENGTH): + if i == 0: + self.Buffer.append(currentstate) + else: + self.Buffer.append(None) + # Initialising index of state saved + if issaved: + self.LastSave = 0 + else: + self.LastSave = -1 + + # Add a new state in buffer + def Buffering(self, currentstate): + self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH + self.Buffer[self.CurrentIndex] = currentstate + # Actualising buffer limits + self.MaxIndex = self.CurrentIndex + if self.MinIndex == self.CurrentIndex: + # If the removed state was the state saved, there is no state saved in the buffer + if self.LastSave == self.MinIndex: + self.LastSave = -1 + self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH + self.MinIndex = max(self.MinIndex, 0) + + # Return current state of buffer + def Current(self): + return self.Buffer[self.CurrentIndex] + + # Change current state to previous in buffer and return new current state + def Previous(self): + if self.CurrentIndex != self.MinIndex: + self.CurrentIndex = (self.CurrentIndex - 1) % UNDO_BUFFER_LENGTH + return self.Buffer[self.CurrentIndex] + return None + + # Change current state to next in buffer and return new current state + def Next(self): + if self.CurrentIndex != self.MaxIndex: + self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH + return self.Buffer[self.CurrentIndex] + return None + + # Return True if current state is the first in buffer + def IsFirst(self): + return self.CurrentIndex == self.MinIndex + + # Return True if current state is the last in buffer + def IsLast(self): + return self.CurrentIndex == self.MaxIndex + + # Note that current state is saved + def CurrentSaved(self): + self.LastSave = self.CurrentIndex + + # Return True if current state is saved + def IsCurrentSaved(self): + return self.LastSave == self.CurrentIndex + + +#------------------------------------------------------------------------------- +# Controler for PLCOpenEditor +#------------------------------------------------------------------------------- + +""" +Class which controls the operations made on the plcopen model and answers to view requests +""" +class PLCControler: + + # Create a new PLCControler + def __init__(self): + self.LastNewIndex = 0 + self.Reset() + + # Reset PLCControler internal variables + def Reset(self): + self.Project = None + self.ProjectBuffer = None + self.FilePath = "" + self.FileName = "" + self.ElementsOpened = [] + self.CurrentElementEditing = None + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + def GetQualifierTypes(self): + return plcopen.QualifierList + + +#------------------------------------------------------------------------------- +# Project management functions +#------------------------------------------------------------------------------- + + # Return if a project is opened + def HasOpenedProject(self): + return self.Project != None + + # Create a new project by replacing the current one + def CreateNewProject(self, name): + # Create the project + self.Project = plcopen.project() + self.Project.setName(name) + # Initialize the project buffer + self.ProjectBuffer = UndoBuffer(self.Copy(self.Project)) + + # Change project name + def SetProjectName(self, name): + self.Project.setName(name) + + # Return project name + def GetProjectName(self): + return self.Project.getName() + + # Return project pou names + def GetProjectPouNames(self): + return [pou.getName() for pou in self.Project.getPous()] + + # Return project pou names + def GetProjectConfigNames(self): + return [config.getName() for config in self.Project.getConfigurations()] + + # Return file path if project is an open file + def GetFilePath(self): + return self.FilePath + + # Return file name and point out if file is up to date + def GetFilename(self): + if self.ProjectBuffer.IsCurrentSaved(): + return self.FileName + else: + return "~%s~"%self.FileName + + # Change file path and save file name or create a default one if file path not defined + def SetFilePath(self, filepath): + self.FilePath = filepath + if filepath == "": + self.LastNewIndex += 1 + self.FileName = "Unnamed%d"%self.LastNewIndex + else: + self.FileName = os.path.splitext(os.path.basename(filepath))[0] + + # Change project properties + def SetProjectProperties(self, values): + self.Project.setFileHeader(values) + + # Return project properties + def GetProjectProperties(self): + return self.Project.getFileHeader() + + # Return project informations + def GetProjectInfos(self): + if self.Project: + infos = {"name": self.Project.getName(), "type": ITEM_PROJECT} + pou_types = {"function": {"name": "Functions", "type": ITEM_UNEDITABLE, "values":[]}, + "functionBlock": {"name": "Function Blocks", "type": ITEM_UNEDITABLE, "values":[]}, + "program": {"name": "Programs", "type": ITEM_UNEDITABLE, "values":[]}} + for pou in self.Project.getPous(): + pou_type = pou.getPouType().getValue() + pou_infos = {"name": pou.getName(), "type": ITEM_POU} + var_types = {"Input": {"name": "Input", "type": ITEM_CLASS, "values": []}, + "Output": {"name": "Output", "type": ITEM_CLASS, "values": []}, + "InOut": {"name": "InOut", "type": ITEM_CLASS, "values": []}, + "External": {"name": "External", "type": ITEM_CLASS, "values": []}, + "Local": {"name": "Local", "type": ITEM_CLASS, "values": []}, + "Temp": {"name": "Temp", "type": ITEM_CLASS, "values": []}, + "Global": {"name": "Global", "type": ITEM_CLASS, "values": []}} + for var in self.GetPouInterfaceVars(pou): + var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []} + if var["Class"] in var_types.keys(): + var_types[var["Class"]]["values"].append(var_values) + pou_values = [] + pou_values.append({"name": "Interface", "type": ITEM_CLASS, + "values": [var_types["Input"], var_types["Output"], var_types["InOut"], var_types["External"]]}) + pou_values.append({"name": "Variables", "type": ITEM_CLASS, + "values": [var_types["Local"], var_types["Temp"]]}) + if pou_type == "program": + pou_values.append(var_types["Global"]) + if pou.getBodyType() == "SFC": + transitions = [] + for transition in pou.getTransitionList(): + transitions.append({"name": transition.getName(), "type": ITEM_TRANSITION, "values": []}) + pou_values.append({"name": "Transitions", "type": ITEM_UNEDITABLE, "values": transitions}) + actions = [] + for action in pou.getActionList(): + actions.append({"name": action.getName(), "type": ITEM_ACTION, "values": []}) + pou_values.append({"name": "Actions", "type": ITEM_UNEDITABLE, "values": actions}) + if pou_type in pou_types: + pou_infos["values"] = pou_values + pou_types[pou_type]["values"].append(pou_infos) + configurations = {"name": "Configurations", "type": ITEM_UNEDITABLE, "values": []} + for config in self.Project.getConfigurations(): + config_name = config.getName() + config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, "values": []} + config_vars = {"name": "Global", "type": ITEM_CLASS, "values": []} + for var in self.GetConfigurationGlobalVars(config_name): + var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []} + config_vars["values"].append(var_values) + resources = {"name": "Resources", "type": ITEM_UNEDITABLE, "values": []} + for resource in config.getResource(): + resource_name = resource.getName() + resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, "values": []} + resource_vars = {"name": "Global", "type": ITEM_CLASS, "values": []} + for var in self.GetConfigurationResourceGlobalVars(config_name, resource_name): + var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []} + resource_vars["values"].append(var_values) + resource_infos["values"].append(resource_vars) + resources["values"].append(resource_infos) + config_infos["values"] = [config_vars, resources] + configurations["values"].append(config_infos) + infos["values"] = [{"name": "Properties", "type": ITEM_UNEDITABLE, "values": []}, + pou_types["function"], pou_types["functionBlock"], + pou_types["program"], configurations] + return infos + return None + + # Refresh the tree of user-defined pou cross-use + def RefreshPouUsingTree(self): + # Reset the tree of user-defined pou cross-use + self.PouUsingTree = {} + if self.Project: + pous = self.Project.getPous() + # Reference all the user-defined pou names and initialize the tree of + # user-defined pou cross-use + pounames = [pou.getName() for pou in pous] + for name in pounames: + self.PouUsingTree[name] = [] + # Analyze each pou + for pou in pous: + name = pou.getName() + bodytype = pou.getBodyType() + # If pou is written in a graphical language + if bodytype in ["FBD","LD","SFC"]: + # Analyze each instance of the pou + for instance in pou.getInstances(): + if isinstance(instance, plcopen.block): + typename = instance.getTypeName() + # Update tree if there is a cross-use + if typename in pounames and name not in self.PouUsingTree[typename]: + self.PouUsingTree[typename].append(name) + # If pou is written in a textual language + elif bodytype in ["IL", "ST"]: + text = pou.getText() + # Search if each pou is mentioned in the pou text + for typename in pounames: + typename_model = re.compile("[ \t\n]%s[ \t\n]"%typename) + # Update tree if there is a cross-use + if typename != name and typename_model.search(text): + self.PouUsingTree[typename].append(name) + + # Return if pou given by name is used by another pou + def PouIsUsed(self, name): + if name in self.PouUsingTree: + return len(self.PouUsingTree[name]) > 0 + return False + + # Return if pou given by name is directly or undirectly used by the reference pou + def PouIsUsedBy(self, name, reference): + if name in self.PouUsingTree: + list = self.PouUsingTree[name] + # Test if pou is directly used by reference + if reference in list: + return True + else: + # Test if pou is undirectly used by reference, by testing if pous + # that directly use pou is directly or undirectly used by reference + used = False + for element in list: + used |= self.PouIsUsedBy(element, reference) + return used + return False + + def GenerateProgram(self): + if self.Project: + program = GenerateCurrentProgram(self.Project) + programfile = open("test.st", "w") + programfile.write(program) + programfile.close() + +#------------------------------------------------------------------------------- +# Project Pous management functions +#------------------------------------------------------------------------------- + + # Add a Pou to Project + def ProjectAddPou(self, name, pou_type, body_type): + # Add the pou to project + self.Project.appendPou(name, pou_type, body_type) + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + # Remove a pou from project + def ProjectRemovePou(self, name): + removed = None + # Search if the pou removed is currently opened + for i, pou in enumerate(self.ElementsOpened): + if pou == name: + removed = i + # If found, remove pou from list of opened pous and actualize current edited + if removed != None: + self.ElementsOpened.pop(removed) + if self.CurrentElementEditing > removed: + self.CurrentElementEditing -= 1 + if len(self.ElementsOpened) > 0: + self.CurrentElementEditing = max(0, min(self.CurrentElementEditing, len(self.ElementsOpened) - 1)) + else: + self.CurrentElementEditing = None + # Remove pou from project + self.Project.removePou(name) + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + # Add a configuration to Project + def ProjectAddConfiguration(self, name): + self.Project.addConfiguration(name) + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + # Remove a configuration from project + def ProjectRemoveConfiguration(self, name): + self.Project.removeConfiguration(name) + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + # Add a resource to a configuration of the Project + def ProjectAddConfigurationResource(self, config, name): + self.Project.addConfigurationResource(config, name) + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + # Remove a resource from a configuration of the project + def ProjectRemoveConfigurationResource(self, config, name): + self.Project.removeConfigurationResource(config, name) + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + # Add a Transition to a Project Pou + def ProjectAddPouTransition(self, pou_name, transition_name, transition_type): + pou = self.Project.getPou(pou_name) + pou.addTransition(transition_name, transition_type) + + # Add a Transition to a Project Pou + def ProjectAddPouAction(self, pou_name, action_name, action_type): + pou = self.Project.getPou(pou_name) + pou.addAction(action_name, action_type) + + # Change the name of a pou + def ChangePouName(self, old_name, new_name): + # Found the pou corresponding to old name and change its name to new name + pou = self.Project.getPou(old_name) + pou.setName(new_name) + # If pou is currently opened, change its name in the list of opened pous + if old_name in self.ElementsOpened: + idx = self.ElementsOpened.index(old_name) + self.ElementsOpened[idx] = new_name + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + # Change the name of a pou transition + def ChangePouTransitionName(self, pou_name, old_name, new_name): + # Found the pou transition corresponding to old name and change its name to new name + pou = self.Project.getPou(pou_name) + transition = pou.getTransition(old_name) + transition.setName(new_name) + # If pou transition is currently opened, change its name in the list of opened elements + old_computedname = self.ComputePouTransitionName(pou_name, old_name) + new_computedname = self.ComputePouTransitionName(pou_name, new_name) + if old_computedname in self.ElementsOpened: + idx = self.ElementsOpened.index(old_computedname) + self.ElementsOpened[idx] = new_computedname + + # Change the name of a pou action + def ChangePouActionName(self, pou_name, old_name, new_name): + # Found the pou action corresponding to old name and change its name to new name + pou = self.Project.getPou(pou_name) + action = pou.getAction(old_name) + action.setName(new_name) + # If pou action is currently opened, change its name in the list of opened elements + old_computedname = self.ComputePouActionName(pou_name, old_name) + new_computedname = self.ComputePouActionName(pou_name, new_name) + if old_computedname in self.ElementsOpened: + idx = self.ElementsOpened.index(old_computedname) + self.ElementsOpened[idx] = new_computedname + + # Change the name of a configuration + def ChangeConfigurationName(self, old_name, new_name): + # Found the configuration corresponding to old name and change its name to new name + configuration = self.Project.getConfiguration(old_name) + configuration.setName(new_name) + # If configuration is currently opened, change its name in the list of opened elements + for idx, element in enumerate(self.ElementsOpened): + self.ElementsOpened[idx] = element.replace(old_name, new_name) + + # Change the name of a configuration resource + def ChangeConfigurationResourceName(self, config_name, old_name, new_name): + # Found the resource corresponding to old name and change its name to new name + resource = self.Project.getConfigurationResource(config_name) + resource.setName(new_name) + # If resource is currently opened, change its name in the list of opened elements + old_computedname = self.ComputeConfigurationResourceName(config_name, old_name) + new_computedname = self.ComputeConfigurationResourceName(config_name, new_name) + if old_computedname in self.ElementsOpened: + idx = self.ElementsOpened.index(old_computedname) + self.ElementsOpened[idx] = new_computedname + + # Return the type of the pou given by its name + def GetPouType(self, name): + # Found the pou correponding to name and return its type + pou = self.Project.getPou(name) + return pou.pouType.getValue() + + # Return pous with SFC language + def GetSFCPous(self): + list = [] + if self.Project: + for pou in self.Project.getPous(): + if pou.getBodyType() == "SFC": + list.append(pou.getName()) + return list + + # Return the body language of the pou given by its name + def GetPouBodyType(self, name): + # Found the pou correponding to name and return its body language + pou = self.Project.getPou(name) + return pou.getBodyType() + + # Return the body language of the transition given by its name + def GetTransitionBodyType(self, pou_name, pou_transition): + # Found the pou correponding to name and return its body language + pou = self.Project.getPou(pou_name) + transition = pou.getTransition(pou_transition) + return transition.getBodyType() + + # Return the body language of the pou given by its name + def GetActionBodyType(self, pou_name, pou_action): + # Found the pou correponding to name and return its body language + pou = self.Project.getPou(pou_name) + action = pou.getAction(pou_action) + return action.getBodyType() + + # Extract varlists from a list of vars + def ExtractVarLists(self, vars): + varlist_list = [] + current_varlist = None + current_type = None + for var in vars: + if current_type != (var["Class"], var["Retain"], var["Constant"]): + current_type = (var["Class"], var["Retain"], var["Constant"]) + current_varlist = plcopen.varList() + varlist_list.append((var["Class"], current_varlist)) + if var["Retain"] == "Yes": + varlist.setRetain(True) + if var["Constant"] == "Yes": + varlist.setConstant(True) + # Create variable and change its properties + tempvar = plcopen.varListPlain_variable() + tempvar.setName(var["Name"]) + var_type = plcopen.dataType() + var_type.setValue(var["Type"]) + tempvar.setType(var_type) + if var["Initial Value"] != "": + value = plcopen.value() + value.setValue(var["Initial Value"]) + tempvar.setInitialValue(value) + if var["Location"] != "": + tempvar.setAddress(var["Location"]) + # Add variable to varList + current_varlist.appendVariable(tempvar) + return varlist_list + + # Replace the configuration globalvars by those given + def SetConfigurationGlobalVars(self, name, vars): + # Found the configuration corresponding to name + configuration = self.Project.getConfiguration(name) + if configuration: + # Set configuration global vars + configuration.setGlobalVars([]) + for vartype, varlist in self.ExtractVarLists(vars): + configuration.globalVars.append(varlist) + self.RefreshBlockTypes() + + # Return the configuration globalvars + def GetConfigurationGlobalVars(self, name): + vars = [] + # Found the configuration corresponding to name + configuration = self.Project.getConfiguration(name) + if configuration: + # Extract variables from every varLists + for varlist in configuration.getGlobalVars(): + for var in varlist.getVariable(): + tempvar = {"Name":var.getName(),"Class":"Global","Type":var.getType().getValue(), + "Location":var.getAddress()} + initial = var.getInitialValue() + if initial: + tempvar["Initial Value"] = initial.getValue() + else: + tempvar["Initial Value"] = "" + if varlist.getRetain(): + tempvar["Retain"] = "Yes" + else: + tempvar["Retain"] = "No" + if varlist.getConstant(): + tempvar["Constant"] = "Yes" + else: + tempvar["Constant"] = "No" + vars.append(tempvar) + return vars + + # Replace the resource globalvars by those given + def SetConfigurationResourceGlobalVars(self, config_name, name, vars): + # Found the resource corresponding to name + resource = self.Project.getConfigurationResource(config_name, name) + # Set resource global vars + if resource: + resource.setGlobalVars([]) + for vartype, varlist in self.ExtractVarLists(vars): + resource.globalVars.append(varlist) + self.RefreshBlockTypes() + + # Return the resource globalvars + def GetConfigurationResourceGlobalVars(self, config_name, name): + vars = [] + # Found the resource corresponding to name + resource = self.Project.getConfigurationResource(config_name, name) + if resource: + # Extract variables from every varLists + for varlist in resource.getGlobalVars(): + for var in varlist.getVariable(): + tempvar = {"Name":var.getName(),"Class":"Global","Type":var.getType().getValue(), + "Location":var.getAddress()} + initial = var.getInitialValue() + if initial: + tempvar["Initial Value"] = initial.getValue() + else: + tempvar["Initial Value"] = "" + if varlist.getRetain(): + tempvar["Retain"] = "Yes" + else: + tempvar["Retain"] = "No" + if varlist.getConstant(): + tempvar["Constant"] = "Yes" + else: + tempvar["Constant"] = "No" + vars.append(tempvar) + return vars + + # Return the interface of the pou given by its name + def GetPouInterfaceVarsByName(self, name): + # Found the pou correponding to name and return the interface + return self.GetPouInterfaceVars(self.Project.getPou(name)) + + # Return the interface for the given pou + def GetPouInterfaceVars(self, pou): + vars = [] + # Verify that the pou has an interface + if pou.interface: + # Extract variables from every varLists + for type, varlist in pou.getVars(): + for var in varlist.getVariable(): + tempvar = {"Name":var.getName(),"Class":type,"Type":var.getType().getValue(), + "Location":var.getAddress()} + initial = var.getInitialValue() + if initial: + tempvar["Initial Value"] = initial.getValue() + else: + tempvar["Initial Value"] = "" + if varlist.getRetain(): + tempvar["Retain"] = "Yes" + else: + tempvar["Retain"] = "No" + if varlist.getConstant(): + tempvar["Constant"] = "Yes" + else: + tempvar["Constant"] = "No" + vars.append(tempvar) + return vars + + # Replace the Pou interface by the one given + def SetPouInterfaceVars(self, name, vars): + # Found the pou corresponding to name and add interface if there isn't one yet + pou = self.Project.getPou(name) + if not pou.interface: + pou.interface = plcopen.pou_interface() + # Set Pou interface + pou.setVars(self.ExtractVarLists(vars)) + self.RefreshBlockTypes() + + # Replace the return type of the pou given by its name (only for functions) + def SetPouInterfaceReturnType(self, name, type): + pou = self.Project.getPou(name) + if not pou.interface: + pou.interface = plcopen.pou_interface() + # If there isn't any return type yet, add it + return_type = pou.interface.getReturnType() + if not return_type: + return_type = plcopen.dataType() + pou.interface.setReturnType(return_type) + # Change return type + return_type.setValue(type) + self.RefreshBlockTypes() + + # Return the return type of the pou given by its name + def GetPouInterfaceReturnTypeByName(self, name): + # Found the pou correponding to name and return the return type + return self.GetPouInterfaceReturnType(self.Project.getPou(name)) + + # Return the return type of the given pou + def GetPouInterfaceReturnType(self, pou): + # Verify that the pou has an interface + if pou.interface: + # Return the return type if there is one + return_type = pou.interface.getReturnType() + if return_type: + return return_type.getValue() + return None + + # Update Block types with user-defined pou added + def RefreshBlockTypes(self): + if BlockTypes[-1]["name"] == "User-defined POUs": + BlockTypes[-1]["list"] = [] + else: + BlockTypes.append({"name" : "User-defined POUs", "list": []}) + if self.Project: + for pou in self.Project.getPous(): + pou_name = pou.getName() + pou_type = pou.pouType.getValue() + if pou_type != "program": + block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False, + "inputs" : [], "outputs" : [], "comment" : ""} + if pou.getInterface(): + for type, varlist in pou.getVars(): + if type == "InOut": + for var in varlist.getVariable(): + block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none")) + block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none")) + elif type == "Input": + for var in varlist.getVariable(): + block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none")) + elif type == "Output": + for var in varlist.getVariable(): + block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none")) + return_type = pou.interface.getReturnType() + if return_type: + block_infos["outputs"].append(("",return_type.getValue(),"none")) + if pou.getBodyType() in ["FBD","LD","SFC"]: + for instance in pou.getInstances(): + if isinstance(instance, plcopen.comment): + block_infos["comment"] = instance.getContentText() + BlockTypes[-1]["list"].append(block_infos) + + # Return Block types checking for recursion + def GetBlockTypes(self): + if self.CurrentElementEditing != None: + current_name = self.ElementsOpened[self.CurrentElementEditing] + words = current_name.split("::") + if len(words) == 1: + name = current_name + else: + name = words[1] + blocktypes = [category for category in BlockTypes[:-1]] + blocktypes.append({"name" : "User-defined POUs", "list": []}) + if self.Project: + pou = self.Project.getPou(name) + name = pou.getName() + type = pou.pouType.getValue() + for blocktype in BlockTypes[-1]["list"]: + if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] == "functionBlock"): + blocktypes[-1]["list"].append(blocktype) + return blocktypes + return [] + + # Return Block types checking for recursion + def GetBlockResource(self): + blocktypes = [] + for category in BlockTypes[:-1]: + for blocktype in category["list"]: + if blocktype["type"] != "function": + blocktypes.append(blocktype["name"]) + if self.Project: + for pou in self.Project.getPous(): + if pou.pouType.getValue() != "function": + blocktypes.append(pou.getName()) + return blocktypes + +#------------------------------------------------------------------------------- +# Project opened Pous management functions +#------------------------------------------------------------------------------- + + # Return the list of pou names + def GetElementsOpenedNames(self): + names = [] + for pou_name in self.ElementsOpened: + words = pou_name.split("::") + if len(words) == 1: + names.append(pou_name) + else: + names.append("%s-%s"%(words[1],words[2])) + return names + + # Compute a pou transition name + def ComputePouTransitionName(self, pou, transition): + return "T::%s::%s" % (pou, transition) + + # Compute a pou action name + def ComputePouActionName(self, pou, action): + return "A::%s::%s" % (pou, action) + + # Compute a pou name + def ComputeConfigurationResourceName(self, config, resource): + return "R::%s::%s" % (config, resource) + + # Open a pou by giving its name + def OpenElementEditing(self, name): + # If pou not opened yet + if name not in self.ElementsOpened: + # Add pou name to list of pou opened and make it current editing + self.ElementsOpened.append(name) + self.CurrentElementEditing = len(self.ElementsOpened) - 1 + return self.CurrentElementEditing + return None + + # Open a pou transition by giving pou and transition names + def OpenPouTransitionEditing(self, pou, transition): + return self.OpenElementEditing(self.ComputePouTransitionName(pou, transition)) + + # Open a pou action by giving pou and action names + def OpenPouActionEditing(self, pou, action): + return self.OpenElementEditing(self.ComputePouActionName(pou, action)) + + # Open a configuration resource by giving configuration and resource names + def OpenConfigurationResourceEditing(self, config, resource): + return self.OpenElementEditing(self.ComputeConfigurationResourceName(config, resource)) + + # Return if pou given by name is opened + def IsElementEditing(self, name): + return name in self.ElementsOpened + + # Return if pou transition given by pou and transition names is opened + def IsPouTransitionEditing(self, pou, transition): + return self.ComputePouTransitionName(pou, transition) in self.ElementsOpened + + # Return if pou action given by pou and action names is opened + def IsPouActionEditing(self, pou, action): + return self.ComputePouActionName(pou, action) in self.ElementsOpened + + # Return if pou action given by pou and action names is opened + def IsConfigurationResourceEditing(self, pou, action): + return self.ComputeConfigurationResourceName(config, resource) in self.ElementsOpened + + # Close current pou editing + def CloseElementEditing(self): + # Remove pou from list of pou opened + self.ElementsOpened.pop(self.CurrentElementEditing) + # Update index of current pou editing + if len(self.ElementsOpened) > 0: + self.CurrentElementEditing = min(self.CurrentElementEditing, len(self.ElementsOpened) - 1) + else: + self.CurrentElementEditing = None + + # Change current pou editing for pou given by name + def ChangeElementEditing(self, name): + # Verify that pou is opened + if name in self.ElementsOpened: + # Change current pou editing + self.CurrentElementEditing = self.ElementsOpened.index(name) + return self.CurrentElementEditing + return None + + # Change current pou editing for transition given by pou and transition names + def ChangePouTransitionEditing(self, pou, transition): + return self.ChangeElementEditing(self.ComputePouTransitionName(pou, transition)) + + # Change current pou editing for action given by pou and action names + def ChangePouActionEditing(self, pou, action): + return self.ChangeElementEditing(self.ComputePouActionName(pou, action)) + + # Change current pou editing for action given by configuration and resource names + def ChangeConfigurationResourceEditing(self, config, resource): + return self.ChangeElementEditing(self.ComputeConfigurationResourceName(config, resource)) + +#------------------------------------------------------------------------------- +# Project opened Pous management functions +#------------------------------------------------------------------------------- + + # Return current pou editing + def GetCurrentElementEditing(self): + # Verify that there's one editing and return it + if self.CurrentElementEditing != None: + name = self.ElementsOpened[self.CurrentElementEditing] + words = name.split("::") + if len(words) == 1: + return self.Project.getPou(name) + else: + if words[0] in ['T', 'A']: + pou = self.Project.getPou(words[1]) + if words[0] == 'T': + return pou.getTransition(words[2]) + elif words[0] == 'A': + return pou.getAction(words[2]) + elif words[0] == 'R': + result = self.Project.getConfigurationResource(words[1], words[2]) + return result + return None + + # Return current pou editing name + def GetCurrentElementEditingName(self): + # Verify that there's one editing and return its name + if self.CurrentElementEditing != None: + name = self.ElementsOpened[self.CurrentElementEditing] + words = name.split("::") + if len(words) == 1: + return name + else: + return words[2] + return None + + # Replace the index of current pou editing by the one given + def RefreshCurrentElementEditing(self, index): + self.CurrentElementEditing = index + + # Return language in which current pou editing is written + def GetCurrentElementEditingBodyType(self): + if self.CurrentElementEditing != None: + name = self.ElementsOpened[self.CurrentElementEditing] + words = name.split("::") + if len(words) == 1: + return self.GetPouBodyType(name) + else: + if words[0] == 'T': + return self.GetTransitionBodyType(words[1], words[2]) + elif words[0] == 'A': + return self.GetActionBodyType(words[1], words[2]) + return None + + # Return the variables of the current pou editing + def GetCurrentElementEditingInterfaceVars(self): + if self.CurrentElementEditing != None: + current_name = self.ElementsOpened[self.CurrentElementEditing] + words = current_name.split("::") + if len(words) == 1: + pou = self.Project.getPou(current_name) + return self.GetPouInterfaceVars(pou) + else: + pou = self.Project.getPou(words[1]) + return self.GetPouInterfaceVars(pou) + return [] + + # Return the return type of the current pou editing + def GetCurrentElementEditingInterfaceReturnType(self): + if self.CurrentElementEditing != None: + current_name = self.ElementsOpened[self.CurrentElementEditing] + words = current_name.split("::") + if len(words) == 1: + pou = self.Project.getPou(current_name) + return self.GetPouInterfaceReturnType(pou) + elif words[0] == 'T': + return "BOOL" + return None + + # Change the text of the current pou editing + def SetCurrentElementEditingText(self, text): + if self.CurrentElementEditing != None: + self.GetCurrentElementEditing().setText(text) + self.RefreshPouUsingTree() + + # Return the current pou editing text + def GetCurrentElementEditingText(self): + if self.CurrentElementEditing != None: + return self.GetCurrentElementEditing().getText() + return "" + + # Return the current pou editing transitions + def GetCurrentElementEditingTransitions(self): + if self.CurrentElementEditing != None: + pou = self.GetCurrentElementEditing() + if pou.getBodyType() == "SFC": + transitions = [] + for transition in pou.getTransitionList(): + transitions.append(transition.getName()) + return transitions + return [] + + # Return the current pou editing transitions + def GetCurrentElementEditingActions(self): + if self.CurrentElementEditing != None: + pou = self.GetCurrentElementEditing() + if pou.getBodyType() == "SFC": + actions = [] + for action in pou.getActionList(): + actions.append(action.getName()) + return actions + return [] + + # Return the current pou editing informations + def GetCurrentElementEditingInstanceInfos(self, id = None, exclude = []): + infos = {} + # if id is defined + if id != None: + instance = self.GetCurrentElementEditing().getInstance(id) + else: + instance = self.GetCurrentElementEditing().getRandomInstance(exclude) + if instance: + if id != None: + infos["id"] = id + else: + infos["id"] = instance.getLocalId() + infos["x"] = instance.getX() + infos["y"] = instance.getY() + infos["height"] = instance.getHeight() + infos["width"] = instance.getWidth() + if isinstance(instance, plcopen.block): + infos["name"] = instance.getInstanceName() + infos["type"] = instance.getTypeName() + infos["connectors"] = {"inputs":[],"outputs":[]} + for variable in instance.inputVariables.getVariable(): + connector = {} + connector["position"] = variable.connectionPointIn.getRelPosition() + connector["negated"] = variable.getNegated() + connector["edge"] = variable.getConnectorEdge() + connector["links"] = [] + connections = variable.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + connector["links"].append(dic) + infos["connectors"]["inputs"].append(connector) + for variable in instance.outputVariables.getVariable(): + connector = {} + connector["position"] = variable.connectionPointOut.getRelPosition() + connector["negated"] = variable.getNegated() + connector["edge"] = variable.getConnectorEdge() + infos["connectors"]["outputs"].append(connector) + elif isinstance(instance, plcopen.inVariable): + infos["name"] = instance.getExpression() + infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"]) + infos["type"] = "input" + infos["connector"] = {} + infos["connector"]["position"] = instance.connectionPointOut.getRelPosition() + infos["connector"]["negated"] = instance.getNegated() + infos["connector"]["edge"] = instance.getConnectorEdge() + elif isinstance(instance, plcopen.outVariable): + infos["name"] = instance.getExpression() + infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"]) + infos["type"] = "output" + infos["connector"] = {} + infos["connector"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connector"]["negated"] = instance.getNegated() + infos["connector"]["edge"] = instance.getConnectorEdge() + infos["connector"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connector"]["links"].append(dic) + elif isinstance(instance, plcopen.inOutVariable): + infos["name"] = instance.getExpression() + infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"]) + infos["type"] = "inout" + infos["connectors"] = {"input":{},"output":{}} + infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition() + infos["connectors"]["output"]["negated"] = instance.getNegatedOut() + infos["connectors"]["output"]["edge"] = instance.getOutputEdge() + infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connectors"]["input"]["negated"] = instance.getNegatedIn() + infos["connectors"]["input"]["edge"] = instance.getInputEdge() + infos["connectors"]["input"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connectors"]["input"]["links"].append(dic) + elif isinstance(instance, plcopen.continuation): + infos["name"] = instance.getName() + infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"]) + infos["type"] = "continuation" + infos["connector"] = {} + infos["connector"]["position"] = instance.connectionPointOut.getRelPosition() + elif isinstance(instance, plcopen.connector): + infos["name"] = instance.getName() + infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"]) + infos["type"] = "connection" + infos["connector"] = {} + infos["connector"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connector"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connector"]["links"].append(dic) + elif isinstance(instance, plcopen.comment): + infos["type"] = "comment" + infos["content"] = instance.getContentText() + elif isinstance(instance, plcopen.leftPowerRail): + infos["type"] = "leftPowerRail" + infos["connectors"] = [] + for connection in instance.getConnectionPointOut(): + connector = {} + connector["position"] = connection.getRelPosition() + infos["connectors"].append(connector) + elif isinstance(instance, plcopen.rightPowerRail): + infos["type"] = "rightPowerRail" + infos["connectors"] = [] + for connection in instance.getConnectionPointIn(): + connector = {} + connector["position"] = connection.getRelPosition() + connector["links"] = [] + for link in connection.getConnections(): + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + connector["links"].append(dic) + infos["connectors"].append(connector) + elif isinstance(instance, plcopen.contact): + infos["type"] = "contact" + infos["name"] = instance.getVariable() + infos["negated"] = instance.getNegated() + infos["edge"] = instance.getContactEdge() + infos["connectors"] = {"input":{},"output":{}} + infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connectors"]["input"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connectors"]["input"]["links"].append(dic) + infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition() + elif isinstance(instance, plcopen.coil): + infos["type"] = "coil" + infos["name"] = instance.getVariable() + infos["negated"] = instance.getNegated() + infos["storage"] = instance.getCoilStorage() + infos["connectors"] = {"input":{},"output":{}} + infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connectors"]["input"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connectors"]["input"]["links"].append(dic) + infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition() + elif isinstance(instance, plcopen.step): + infos["type"] = "step" + infos["name"] = instance.getName() + infos["initial"] = instance.getInitialStep() + infos["connectors"] = {} + if instance.connectionPointIn: + infos["connectors"]["input"] = {} + infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connectors"]["input"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connectors"]["input"]["links"].append(dic) + if instance.connectionPointOut: + infos["connectors"]["output"] = {"position" : instance.connectionPointOut.getRelPosition()} + if instance.connectionPointOutAction: + infos["connectors"]["action"] = {"position" : instance.connectionPointOutAction.getRelPosition()} + elif isinstance(instance, plcopen.transition): + infos["type"] = "transition" + condition = instance.getConditionContent() + infos["condition_type"] = condition["type"] + infos["condition"] = condition["value"] + infos["connectors"] = {"input":{},"output":{}} + infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connectors"]["input"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connectors"]["input"]["links"].append(dic) + infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition() + elif isinstance(instance, (plcopen.selectionDivergence, plcopen.simultaneousDivergence)): + if isinstance(instance, plcopen.selectionDivergence): + infos["type"] = "selectionDivergence" + else: + infos["type"] = "simultaneousDivergence" + infos["connectors"] = {"inputs":[],"outputs":[]} + connector = {} + connector["position"] = instance.connectionPointIn.getRelPosition() + connector["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + connector["links"].append(dic) + infos["connectors"]["inputs"].append(connector) + for sequence in instance.getConnectionPointOut(): + connector = {} + connector["position"] = sequence.getRelPosition() + infos["connectors"]["outputs"].append(connector) + elif isinstance(instance, (plcopen.selectionConvergence, plcopen.simultaneousConvergence)): + if isinstance(instance, plcopen.selectionConvergence): + infos["type"] = "selectionConvergence" + else: + infos["type"] = "simultaneousConvergence" + infos["connectors"] = {"inputs":[],"outputs":[]} + for sequence in instance.getConnectionPointIn(): + connector = {} + connector["position"] = sequence.getRelPosition() + connector["links"] = [] + connections = sequence.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + connector["links"].append(dic) + infos["connectors"]["inputs"].append(connector) + connector = {} + connector["position"] = instance.connectionPointOut.getRelPosition() + infos["connectors"]["outputs"].append(connector) + elif isinstance(instance, plcopen.jumpStep): + infos["type"] = "jump" + infos["target"] = instance.getTargetName() + infos["connector"] = {} + infos["connector"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connector"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connector"]["links"].append(dic) + elif isinstance(instance, plcopen.actionBlock): + infos["type"] = "actionBlock" + infos["actions"] = instance.getActions() + infos["connector"] = {} + infos["connector"]["position"] = instance.connectionPointIn.getRelPosition() + infos["connector"]["links"] = [] + connections = instance.connectionPointIn.getConnections() + if connections: + for link in connections: + dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()} + infos["connector"]["links"].append(dic) + return infos + return False + + # Return the variable type of the given pou + def GetPouVarValueType(self, pou, varname): + for type, varlist in pou.getVars(): + for var in varlist.getVariable(): + if var.getName() == varname: + return var.getType() + return "" + + def SetConnectionWires(self, connection, connector): + wires = connector.GetWires() + idx = 0 + for wire, handle in wires: + points = wire.GetPoints(handle != 0) + if handle == 0: + refLocalId = wire.GetConnectedId(-1) + else: + refLocalId = wire.GetConnectedId(0) + if refLocalId != None: + connection.addConnection() + connection.setConnectionId(idx, refLocalId) + connection.setConnectionPoints(idx, points) + idx += 1 + + def AddCurrentElementEditingBlock(self, id): + block = plcopen.block() + block.setLocalId(id) + self.GetCurrentElementEditing().addInstance("block", block) + self.RefreshPouUsingTree() + + def SetCurrentElementEditingBlockInfos(self, id, infos): + block = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "name": + block.setInstanceName(value) + elif param == "type": + block.setTypeName(value) + elif param == "height": + block.setHeight(value) + elif param == "width": + block.setWidth(value) + elif param == "x": + block.setX(value) + elif param == "y": + block.setY(value) + elif param == "connectors": + block.inputVariables.setVariable([]) + block.outputVariables.setVariable([]) + for connector in value["inputs"]: + variable = plcopen.inputVariables_variable() + variable.setFormalParameter(connector.GetName()) + if connector.IsNegated(): + variable.setNegated(True) + if connector.GetEdge() != "none": + variable.setConnectorEdge(connector.GetEdge()) + position = connector.GetRelPosition() + variable.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(variable.connectionPointIn, connector) + block.inputVariables.appendVariable(variable) + for connector in value["outputs"]: + variable = plcopen.outputVariables_variable() + variable.setFormalParameter(connector.GetName()) + if connector.IsNegated(): + variable.setNegated(True) + if connector.GetEdge() != "none": + variable.setConnectorEdge(connector.GetEdge()) + position = connector.GetRelPosition() + variable.addConnectionPointOut() + variable.connectionPointOut.setRelPosition(position.x, position.y) + block.outputVariables.appendVariable(variable) + self.RefreshPouUsingTree() + + def AddCurrentElementEditingVariable(self, id, type): + if type == INPUT: + name = "inVariable" + variable = plcopen.inVariable() + elif type == OUTPUT: + name = "outVariable" + variable = plcopen.outVariable() + elif type == INOUT: + name = "inOutVariable" + variable = plcopen.inOutVariable() + variable.setLocalId(id) + self.GetCurrentElementEditing().addInstance(name, variable) + + def SetCurrentElementEditingVariableInfos(self, id, infos): + variable = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "name": + variable.setExpression(value) + elif param == "height": + variable.setHeight(value) + elif param == "width": + variable.setWidth(value) + elif param == "x": + variable.setX(value) + elif param == "y": + variable.setY(value) + elif param == "connectors": + if isinstance(variable, plcopen.inVariable): + if value["output"].IsNegated(): + variable.setNegated(True) + if value["output"].GetEdge() != "none": + variable.setConnectorEdge(value["output"].GetEdge()) + position = value["output"].GetRelPosition() + variable.addConnectionPointOut() + variable.connectionPointOut.setRelPosition(position.x, position.y) + elif isinstance(variable, plcopen.outVariable): + if value["input"].IsNegated(): + variable.setNegated(True) + if value["input"].GetEdge() != "none": + variable.setConnectorEdge(value["input"].GetEdge()) + position = value["input"].GetRelPosition() + variable.addConnectionPointIn() + variable.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(variable.connectionPointIn, value["input"]) + elif isinstance(variable, plcopen.inOutVariable): + if value["input"].IsNegated(): + variable.setNegatedIn(True) + if value["input"].GetEdge() != "none": + variable.setInputEdge(value["input"].GetEdge()) + if value["output"].IsNegated(): + variable.setNegatedOut(True) + if value["output"].GetEdge() != "none": + variable.setOutputEdge(value["output"].GetEdge()) + position = value["output"].GetRelPosition() + variable.addConnectionPointOut() + variable.connectionPointOut.setRelPosition(position.x, position.y) + position = value["input"].GetRelPosition() + variable.addConnectionPointIn() + variable.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(variable.connectionPointIn, value["input"]) + + + def AddCurrentElementEditingConnection(self, id, type): + if type == CONNECTOR: + name = "connector" + connection = plcopen.connector() + elif type == CONTINUATION: + name = "continuation" + connection = plcopen.continuation() + connection.setLocalId(id) + self.GetCurrentElementEditing().addInstance(name, connection) + + def SetCurrentElementEditingConnectionInfos(self, id, infos): + connection = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "name": + connection.setName(value) + elif param == "height": + connection.setHeight(value) + elif param == "width": + connection.setWidth(value) + elif param == "x": + connection.setX(value) + elif param == "y": + connection.setY(value) + elif param == "connector": + position = value.GetRelPosition() + if isinstance(connection, plcopen.continuation): + connection.addConnectionPointOut() + connection.connectionPointOut.setRelPosition(position.x, position.y) + elif isinstance(connection, plcopen.connector): + connection.addConnectionPointIn() + connection.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(connection.connectionPointIn, value) + + def AddCurrentElementEditingComment(self, id): + comment = plcopen.comment() + comment.setLocalId(id) + self.GetCurrentElementEditing().addInstance("comment", comment) + + def SetCurrentElementEditingCommentInfos(self, id, infos): + comment = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "content": + comment.setContentText(value) + elif param == "height": + comment.setHeight(value) + elif param == "width": + comment.setWidth(value) + elif param == "x": + comment.setX(value) + elif param == "y": + comment.setY(value) + + def AddCurrentElementEditingPowerRail(self, id, type): + if type == LEFTRAIL: + name = "leftPowerRail" + powerrail = plcopen.leftPowerRail() + elif type == RIGHTRAIL: + name = "rightPowerRail" + powerrail = plcopen.rightPowerRail() + powerrail.setLocalId(id) + self.GetCurrentElementEditing().addInstance(name, powerrail) + + def SetCurrentElementEditingPowerRailInfos(self, id, infos): + powerrail = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "height": + powerrail.setHeight(value) + elif param == "width": + powerrail.setWidth(value) + elif param == "x": + powerrail.setX(value) + elif param == "y": + powerrail.setY(value) + elif param == "connectors": + if isinstance(powerrail, plcopen.leftPowerRail): + powerrail.setConnectionPointOut([]) + for connector in value: + position = connector.GetRelPosition() + connection = plcopen.leftPowerRail_connectionPointOut() + connection.setRelPosition(position.x, position.y) + powerrail.connectionPointOut.append(connection) + elif isinstance(powerrail, plcopen.rightPowerRail): + powerrail.setConnectionPointIn([]) + for connector in value: + position = connector.GetRelPosition() + connection = plcopen.connectionPointIn() + connection.setRelPosition(position.x, position.y) + self.SetConnectionWires(connection, connector) + powerrail.connectionPointIn.append(connection) + + def AddCurrentElementEditingContact(self, id): + contact = plcopen.contact() + contact.setLocalId(id) + self.GetCurrentElementEditing().addInstance("contact", contact) + + def SetCurrentElementEditingContactInfos(self, id, infos): + contact = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "name": + contact.setVariable(value) + elif param == "type": + if value == CONTACT_NORMAL: + contact.setNegated(False) + contact.setContactEdge("none") + elif value == CONTACT_REVERSE: + contact.setNegated(True) + contact.setContactEdge("none") + elif value == CONTACT_RISING: + contact.setNegated(False) + contact.setContactEdge("rising") + elif value == CONTACT_FALLING: + contact.setNegated(False) + contact.setContactEdge("falling") + elif param == "height": + contact.setHeight(value) + elif param == "width": + contact.setWidth(value) + elif param == "x": + contact.setX(value) + elif param == "y": + contact.setY(value) + elif param == "connectors": + input_connector = value["input"] + position = input_connector.GetRelPosition() + contact.addConnectionPointIn() + contact.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(contact.connectionPointIn, input_connector) + output_connector = value["output"] + position = output_connector.GetRelPosition() + contact.addConnectionPointOut() + contact.connectionPointOut.setRelPosition(position.x, position.y) + + def AddCurrentElementEditingCoil(self, id): + coil = plcopen.coil() + coil.setLocalId(id) + self.GetCurrentElementEditing().addInstance("coil", coil) + + def SetCurrentElementEditingCoilInfos(self, id, infos): + coil = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "name": + coil.setVariable(value) + elif param == "type": + if value == COIL_NORMAL: + coil.setNegated(False) + coil.setCoilStorage("none") + elif value == COIL_REVERSE: + coil.setNegated(True) + coil.setCoilStorage("none") + elif value == COIL_SET: + coil.setNegated(False) + coil.setCoilStorage("set") + elif value == COIL_RESET: + coil.setNegated(False) + coil.setCoilStorage("reset") + elif param == "height": + coil.setHeight(value) + elif param == "width": + coil.setWidth(value) + elif param == "x": + coil.setX(value) + elif param == "y": + coil.setY(value) + elif param == "connectors": + input_connector = value["input"] + position = input_connector.GetRelPosition() + coil.addConnectionPointIn() + coil.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(coil.connectionPointIn, input_connector) + output_connector = value["output"] + position = output_connector.GetRelPosition() + coil.addConnectionPointOut() + coil.connectionPointOut.setRelPosition(position.x, position.y) + + def AddCurrentElementEditingStep(self, id): + step = plcopen.step() + step.setLocalId(id) + self.GetCurrentElementEditing().addInstance("step", step) + + def SetCurrentElementEditingStepInfos(self, id, infos): + step = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "name": + step.setName(value) + elif param == "initial": + step.setInitialStep(value) + elif param == "height": + step.setHeight(value) + elif param == "width": + step.setWidth(value) + elif param == "x": + step.setX(value) + elif param == "y": + step.setY(value) + elif param == "connectors": + input_connector = value["input"] + if input_connector: + position = input_connector.GetRelPosition() + step.addConnectionPointIn() + step.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(step.connectionPointIn, input_connector) + else: + step.deleteConnectionPointIn() + output_connector = value["output"] + if output_connector: + position = output_connector.GetRelPosition() + step.addConnectionPointOut() + step.connectionPointOut.setRelPosition(position.x, position.y) + else: + step.deleteConnectionPointOut() + action_connector = value["action"] + if action_connector: + position = action_connector.GetRelPosition() + step.addConnectionPointOutAction() + step.connectionPointOutAction.setRelPosition(position.x, position.y) + else: + step.deleteConnectionPointOutAction() + + def AddCurrentElementEditingTransition(self, id): + transition = plcopen.transition() + transition.setLocalId(id) + self.GetCurrentElementEditing().addInstance("transition", transition) + + def SetCurrentElementEditingTransitionInfos(self, id, infos): + transition = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "type" and "condition" in infos: + transition.setConditionContent(value, infos["condition"]) + elif param == "height": + transition.setHeight(value) + elif param == "width": + transition.setWidth(value) + elif param == "x": + transition.setX(value) + elif param == "y": + transition.setY(value) + elif param == "connectors": + input_connector = value["input"] + position = input_connector.GetRelPosition() + transition.addConnectionPointIn() + transition.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(transition.connectionPointIn, input_connector) + output_connector = value["output"] + position = output_connector.GetRelPosition() + transition.addConnectionPointOut() + transition.connectionPointOut.setRelPosition(position.x, position.y) + + def AddCurrentElementEditingDivergence(self, id, type): + if type == SELECTION_DIVERGENCE: + name = "selectionDivergence" + divergence = plcopen.selectionDivergence() + elif type == SELECTION_CONVERGENCE: + name = "selectionConvergence" + divergence = plcopen.selectionConvergence() + elif type == SIMULTANEOUS_DIVERGENCE: + name = "simultaneousDivergence" + divergence = plcopen.simultaneousDivergence() + elif type == SIMULTANEOUS_CONVERGENCE: + name = "simultaneousConvergence" + divergence = plcopen.simultaneousConvergence() + divergence.setLocalId(id) + self.GetCurrentElementEditing().addInstance(name, divergence) + + def SetCurrentElementEditingDivergenceInfos(self, id, infos): + divergence = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "height": + divergence.setHeight(value) + elif param == "width": + divergence.setWidth(value) + elif param == "x": + divergence.setX(value) + elif param == "y": + divergence.setY(value) + elif param == "connectors": + input_connectors = value["inputs"] + if isinstance(divergence, (plcopen.selectionDivergence, plcopen.simultaneousDivergence)): + position = input_connectors[0].GetRelPosition() + divergence.addConnectionPointIn() + divergence.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(divergence.connectionPointIn, input_connectors[0]) + else: + divergence.setConnectionPointIn([]) + for input_connector in input_connectors: + position = input_connector.GetRelPosition() + if isinstance(divergence, plcopen.selectionConvergence): + connection = plcopen.selectionConvergence_connectionPointIn() + else: + connection = plcopen.connectionPointIn() + connection.setRelPosition(position.x, position.y) + self.SetConnectionWires(connection, input_connector) + divergence.appendConnectionPointIn(connection) + output_connectors = value["outputs"] + if isinstance(divergence, (plcopen.selectionConvergence, plcopen.simultaneousConvergence)): + position = output_connectors[0].GetRelPosition() + divergence.addConnectionPointOut() + divergence.connectionPointOut.setRelPosition(position.x, position.y) + else: + divergence.setConnectionPointOut([]) + for output_connector in output_connectors: + position = output_connector.GetRelPosition() + if isinstance(divergence, plcopen.selectionDivergence): + connection = plcopen.selectionDivergence_connectionPointOut() + else: + connection = plcopen.simultaneousDivergence_connectionPointOut() + connection.setRelPosition(position.x, position.y) + divergence.appendConnectionPointOut(connection) + + def AddCurrentElementEditingJump(self, id): + jump = plcopen.jumpStep() + jump.setLocalId(id) + self.GetCurrentElementEditing().addInstance("jumpStep", jump) + + def SetCurrentElementEditingJumpInfos(self, id, infos): + jump = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "target": + jump.setTargetName(value) + elif param == "height": + jump.setHeight(value) + elif param == "width": + jump.setWidth(value) + elif param == "x": + jump.setX(value) + elif param == "y": + jump.setY(value) + elif param == "connector": + position = value.GetRelPosition() + jump.addConnectionPointIn() + jump.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(jump.connectionPointIn, value) + + def AddCurrentElementEditingActionBlock(self, id): + actionBlock = plcopen.actionBlock() + actionBlock.setLocalId(id) + self.GetCurrentElementEditing().addInstance("actionBlock", actionBlock) + + def SetCurrentElementEditingActionBlockInfos(self, id, infos): + actionBlock = self.GetCurrentElementEditing().getInstance(id) + for param, value in infos.items(): + if param == "actions": + actionBlock.setActions(value) + elif param == "height": + actionBlock.setHeight(value) + elif param == "width": + actionBlock.setWidth(value) + elif param == "x": + actionBlock.setX(value) + elif param == "y": + actionBlock.setY(value) + elif param == "connector": + position = value.GetRelPosition() + actionBlock.addConnectionPointIn() + actionBlock.connectionPointIn.setRelPosition(position.x, position.y) + self.SetConnectionWires(actionBlock.connectionPointIn, value) + + def RemoveCurrentElementEditingInstance(self, id): + self.GetCurrentElementEditing().removeInstance(id) + self.RefreshPouUsingTree() + + def GetCurrentResourceEditingVariables(self): + varlist = [] + name = self.ElementsOpened[self.CurrentElementEditing] + words = name.split("::") + for var in self.GetConfigurationGlobalVars(words[1]): + if var["Type"] == "BOOL": + varlist.append(var["Name"]) + for var in self.GetConfigurationResourceGlobalVars(words[1], words[2]): + if var["Type"] == "BOOL": + varlist.append(var["Name"]) + return varlist + + def SetCurrentResourceEditingInfos(self, tasks, instances): + resource = self.GetCurrentElementEditing() + resource.setTask([]) + resource.setPouInstance([]) + task_list = {} + for task in tasks: + new_task = plcopen.resource_task() + new_task.setName(task["Name"]) + if task["Single"] != "": + new_task.setSingle(task["Single"]) + if task["Interval"] != "": + new_task.setInterval(task["Interval"]) + new_task.priority.setValue(int(task["Priority"])) + if task["Name"] != "": + task_list[task["Name"]] = new_task + resource.appendTask(new_task) + for instance in instances: + new_instance = plcopen.pouInstance() + new_instance.setName(instance["Name"]) + new_instance.setType(instance["Type"]) + if instance["Task"] != "": + task_list[instance["Task"]].appendPouInstance(new_instance) + else: + resource.appendPouInstance(new_instance) + + def GetCurrentResourceEditingInfos(self): + resource = self.GetCurrentElementEditing() + tasks = resource.getTask() + instances = resource.getPouInstance() + tasks_data = [] + instances_data = [] + for task in tasks: + new_task = {} + new_task["Name"] = task.getName() + single = task.getSingle() + if single: + new_task["Single"] = single + else: + new_task["Single"] = "" + interval = task.getInterval() + if interval: + new_task["Interval"] = interval + else: + new_task["Interval"] = "" + new_task["Priority"] = str(task.priority.getValue()) + tasks_data.append(new_task) + for instance in task.getPouInstance(): + new_instance = {} + new_instance["Name"] = instance.getName() + new_instance["Type"] = instance.getType() + new_instance["Task"] = task.getName() + instances_data.append(new_instance) + for instance in instances: + new_instance = {} + new_instance["Name"] = instance.getName() + new_instance["Type"] = instance.getType() + new_instance["Task"] = "" + instances_data.append(new_instance) + return tasks_data, instances_data + + def OpenXMLFile(self, filepath): + if sys: + sys.stdout = plcopen.HolePseudoFile() + tree = pyxsval.parseAndValidate(filepath, "plcopen/TC6_XML_V10_B.xsd") + if sys: + sys.stdout = sys.__stdout__ + + self.Project = plcopen.project() + self.Project.loadXMLTree(tree.getTree().childNodes[0]) + self.UndoBuffer = UndoBuffer(self.Copy(self.Project), True) + self.SetFilePath(filepath) + self.ElementsOpened = [] + self.CurrentElementEditing = None + self.RefreshPouUsingTree() + self.RefreshBlockTypes() + + def SaveXMLFile(self, filepath = None): + if not filepath and self.FilePath == "": + return False + else: + text = "\n" + extras = {"xmlns" : "http://www.plcopen.org/xml/tc6.xsd", + "xmlns:xhtml" : "http://www.w3.org/1999/xhtml", + "xmlns:xsi" : "http://www.w3.org/2001/XMLSchema-instance", + "xsi:schemaLocation" : "http://www.plcopen.org/xml/tc6.xsd http://www.plcopen.org/xml/tc6.xsd"} + text += self.Project.generateXMLText("project", 0, extras) + + if sys: + sys.stdout = plcopen.HolePseudoFile() + pyxsval.parseAndValidateString(text, open("plcopen/TC6_XML_V10_B.xsd","r").read()) + if sys: + sys.stdout = sys.__stdout__ + + if filepath: + xmlfile = open(filepath,"w") + else: + xmlfile = open(self.FilePath,"w") + xmlfile.write(text) + xmlfile.close() + self.UndoBuffer.CurrentSaved() + if filepath: + self.SetFilePath(filepath) + return True + +#------------------------------------------------------------------------------- +# Current Buffering Management Functions +#------------------------------------------------------------------------------- + + """ + Return a copy of the project + """ + def Copy(self, model): + return cPickle.loads(cPickle.dumps(model)) + + def BufferProject(self): + self.UndoBuffer.Buffering(self.Copy(self)) + + def ProjectIsSaved(self): + return self.UndoBuffer.IsCurrentSaved() + + def LoadPrevious(self): + self.Project = self.Copy(self.UndoBuffer.Previous()) + self.RefreshElementsOpened() + + def LoadNext(self): + self.Project = self.Copy(self.UndoBuffer.Next()) + self.RefreshElementsOpened() + + def GetBufferState(self): + first = self.UndoBuffer.IsFirst() + last = self.UndoBuffer.IsLast() + return not first, not last