Fix bug when displaying errors when generating textual program in standalone mode
#!/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) 2007: 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 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
#General Public License for more details.
#
#You should have received a copy of the GNU 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 xml.dom import minidom
from types import StringType, UnicodeType
import cPickle
import os,sys,re
import datetime
from time import localtime
from plcopen import plcopen
from plcopen.structures import *
from graphics.GraphicCommons import *
from PLCGenerator import *
duration_model = re.compile("(?:([0-9]{1,2})h)?(?:([0-9]{1,2})m(?!s))?(?:([0-9]{1,2})s)?(?:([0-9]{1,3}(?:\.[0-9]*)?)ms)?")
ITEMS_EDITABLE = [ITEM_PROJECT,
ITEM_POU,
ITEM_VARIABLE,
ITEM_TRANSITION,
ITEM_ACTION,
ITEM_CONFIGURATION,
ITEM_RESOURCE,
ITEM_DATATYPE
] = range(8)
ITEMS_UNEDITABLE = [ITEM_DATATYPES,
ITEM_FUNCTION,
ITEM_FUNCTIONBLOCK,
ITEM_PROGRAM,
ITEM_TRANSITIONS,
ITEM_ACTIONS,
ITEM_CONFIGURATIONS,
ITEM_RESOURCES,
ITEM_PROPERTIES
] = range(8, 17)
ITEMS_VARIABLE = [ITEM_VAR_LOCAL,
ITEM_VAR_GLOBAL,
ITEM_VAR_EXTERNAL,
ITEM_VAR_TEMP,
ITEM_VAR_INPUT,
ITEM_VAR_OUTPUT,
ITEM_VAR_INOUT
] = range(17, 24)
VAR_CLASS_INFOS = {"Local" : (plcopen.interface_localVars, ITEM_VAR_LOCAL),
"Global" : (plcopen.interface_globalVars, ITEM_VAR_GLOBAL),
"External" : (plcopen.interface_externalVars, ITEM_VAR_EXTERNAL),
"Temp" : (plcopen.interface_tempVars, ITEM_VAR_TEMP),
"Input" : (plcopen.interface_inputVars, ITEM_VAR_INPUT),
"Output" : (plcopen.interface_outputVars, ITEM_VAR_OUTPUT),
"InOut" : (plcopen.interface_inOutVars, ITEM_VAR_INOUT)
}
LOCATIONS_ITEMS = [LOCATION_PLUGIN,
LOCATION_MODULE,
LOCATION_GROUP,
LOCATION_VAR_INPUT,
LOCATION_VAR_OUTPUT,
LOCATION_VAR_MEMORY] = range(6)
ScriptDirectory = os.path.split(os.path.realpath(__file__))[0]
def GetUneditableNames():
_ = lambda x:x
return [_("User-defined POUs"), _("Functions"), _("Function Blocks"),
_("Programs"), _("Data Types"), _("Transitions"), _("Actions"),
_("Configurations"), _("Resources"), _("Properties")]
UNEDITABLE_NAMES = GetUneditableNames()
[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS,
DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS,
RESOURCES, PROPERTIES] = UNEDITABLE_NAMES
#-------------------------------------------------------------------------------
# Undo Buffer for PLCOpenEditor
#-------------------------------------------------------------------------------
# Length of the buffer
UNDO_BUFFER_LENGTH = 20
"""
Class implementing a buffer of changes made on the current editing model
"""
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.ProjectBufferEnabled = True
self.ProjectBuffer = None
self.ProjectSaved = True
self.Buffering = False
self.FilePath = ""
self.FileName = ""
self.ProgramChunks = []
self.ProgramOffset = 0
self.NextCompiledProject = None
self.CurrentCompiledProject = None
self.PluginTypes = []
self.ProgramFilePath = ""
def GetQualifierTypes(self):
return plcopen.QualifierList
def GetProject(self, debug = False):
if debug and self.CurrentCompiledProject is not None:
return self.CurrentCompiledProject
else:
return self.Project
#-------------------------------------------------------------------------------
# Project management functions
#-------------------------------------------------------------------------------
# Return if a project is opened
def HasOpenedProject(self):
return self.Project is not None
# Create a new project by replacing the current one
def CreateNewProject(self, properties):
# Create the project
self.Project = plcopen.project()
properties["creationDateTime"] = datetime.datetime(*localtime()[:6])
self.Project.setfileHeader(properties)
self.Project.setcontentHeader(properties)
self.SetFilePath("")
# Initialize the project buffer
self.CreateProjectBuffer(False)
self.ProgramChunks = []
self.ProgramOffset = 0
self.NextCompiledProject = self.Copy(self.Project)
self.CurrentCompiledProject = None
self.Buffering = False
# Return project data type names
def GetProjectDataTypeNames(self, debug = False):
project = self.GetProject(debug)
if project is not None:
return [datatype.getname() for datatype in project.getdataTypes()]
return []
# Return project pou names
def GetProjectPouNames(self, debug = False):
project = self.GetProject(debug)
if project is not None:
return [pou.getname() for pou in project.getpous()]
return []
# Return project pou names
def GetProjectConfigNames(self, debug = False):
project = self.GetProject(debug)
if project is not None:
return [config.getname() for config in project.getconfigurations()]
return []
# Return project pou variables
def GetProjectPouVariables(self, pou_name = None, debug = False):
variables = []
project = self.GetProject(debug)
if project is not None:
for pou in project.getpous():
if pou_name is None or pou_name == pou.getname():
variables.extend([var["Name"] for var in self.GetPouInterfaceVars(pou, debug)])
for transition in pou.gettransitionList():
variables.append(transition.getname())
for action in pou.getactionList():
variables.append(action.getname())
return variables
# Return file path if project is an open file
def GetFilePath(self):
return self.FilePath
# Return file path if project is an open file
def GetProgramFilePath(self):
return self.ProgramFilePath
# Return file name and point out if file is up to date
def GetFilename(self):
if self.Project is not None:
if self.ProjectIsSaved():
return self.FileName
else:
return "~%s~"%self.FileName
return ""
# 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, name = None, properties = None):
if self.Project is not None:
if name is not None:
self.Project.setname(name)
if properties is not None:
self.Project.setfileHeader(properties)
self.Project.setcontentHeader(properties)
if name is not None or properties is not None:
self.BufferProject()
# Return project properties
def GetProjectProperties(self, debug = False):
project = self.GetProject(debug)
if project is not None:
properties = project.getfileHeader()
properties.update(project.getcontentHeader())
return properties
return None
# Return project informations
def GetProjectInfos(self, debug = False):
project = self.GetProject(debug)
if project is not None:
infos = {"name": project.getname(), "type": ITEM_PROJECT}
datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values":[]}
for datatype in project.getdataTypes():
datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE,
"tagname": self.ComputeDataTypeName(datatype.getname()), "values": []})
pou_types = {"function": {"name": FUNCTIONS, "type": ITEM_FUNCTION, "values":[]},
"functionBlock": {"name": FUNCTION_BLOCKS, "type": ITEM_FUNCTIONBLOCK, "values":[]},
"program": {"name": PROGRAMS, "type": ITEM_PROGRAM, "values":[]}}
for pou in project.getpous():
pou_type = pou.getpouType()
pou_infos = {"name": pou.getname(), "type": ITEM_POU,
"tagname": self.ComputePouName(pou.getname())}
pou_values = []
if pou.getbodyType() == "SFC":
transitions = []
for transition in pou.gettransitionList():
transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION,
"tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()),
"values": []})
pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions})
actions = []
for action in pou.getactionList():
actions.append({"name": action.getname(), "type": ITEM_ACTION,
"tagname": self.ComputePouActionName(pou.getname(), action.getname()),
"values": []})
pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "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_CONFIGURATIONS, "values": []}
for config in project.getconfigurations():
config_name = config.getname()
config_infos = {"name": config_name, "type": ITEM_CONFIGURATION,
"tagname": self.ComputeConfigurationName(config.getname()),
"values": []}
resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []}
for resource in config.getresource():
resource_name = resource.getname()
resource_infos = {"name": resource_name, "type": ITEM_RESOURCE,
"tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()),
"values": []}
resources["values"].append(resource_infos)
config_infos["values"] = [resources]
configurations["values"].append(config_infos)
infos["values"] = [{"name": PROPERTIES, "type": ITEM_PROPERTIES, "values": []},
datatypes, pou_types["function"], pou_types["functionBlock"],
pou_types["program"], configurations]
return infos
return None
# Return project topology informations
def GetProjectTopology(self, debug = False):
project = self.GetProject(debug)
if project is not None:
infos = {"name": project.getname(), "type": ITEM_PROJECT, "values" : []}
for config in project.getconfigurations():
config_infos = {"name" : config.getname(), "type": ITEM_CONFIGURATION, "values" : []}
for resource in config.getresource():
resource_infos = {"name" : resource.getname(), "type": ITEM_RESOURCE, "values": []}
for task in resource.gettask():
for pou in task.getpouInstance():
instance_infos = self.GetPouTopology(pou.getname(), pou.gettypeName(), debug=debug)
if instance_infos is not None:
resource_infos["values"].append(instance_infos)
for pou in resource.getpouInstance():
instance_infos = self.GetPouTopology(pou.getname(), pou.gettypeName(), debug=debug)
if instance_infos is not None:
resource_infos["values"].append(instance_infos)
for varlist in resource.getglobalVars():
for variable in varlist.getvariable():
vartype_content = variable.gettype().getcontent()
if vartype_content["name"] == "derived":
var_infos = self.GetPouTopology(variable.getname(), vartype_content["value"].getname(), True, debug)
if var_infos is not None:
resource_infos["values"].append(var_infos)
elif vartype_content["name"] in ["string", "wstring"]:
resource_infos["values"].append({"name" : variable.getname(),
"elmt_type" : vartype_content["name"].upper(),
"type" : ITEM_VAR_GLOBAL, "values" : []})
else:
resource_infos["values"].append({"name" : variable.getname(),
"elmt_type" : vartype_content["name"],
"type" : ITEM_VAR_GLOBAL, "values" : []})
config_infos["values"].append(resource_infos)
for varlist in config.getglobalVars():
for variable in varlist.getvariable():
vartype_content = variable.gettype().getcontent()
if vartype_content["name"] == "derived":
var_infos = self.GetPouTopology(variable.getname(), vartype_content["value"].getname(), True, debug)
if var_infos is not None:
config_infos["values"].append(var_infos)
elif vartype_content["name"] in ["string", "wstring"]:
config_infos["values"].append({"name" : variable.getname(),
"elmt_type" : vartype_content["name"].upper(),
"type" : ITEM_VAR_GLOBAL, "values" : []})
else:
config_infos["values"].append({"name" : variable.getname(),
"elmt_type" : vartype_content["name"],
"type" : ITEM_VAR_GLOBAL, "values" : []})
infos["values"].append(config_infos)
return infos
return None
# Return pou topology informations
def GetPouTopology(self, name, type, global_var = False, debug = False):
project = self.GetProject(debug)
if project is not None:
pou = project.getpou(type)
if pou is not None:
pou_type = pou.getpouType()
if pou_type == "function":
return None
elif pou_type == "program":
pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_PROGRAM,
"tagname" : self.ComputePouName(pou.getname()), "values" : []}
else:
pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_FUNCTIONBLOCK,
"tagname" : self.ComputePouName(pou.getname()), "values" : []}
if pou.getbodyType() == "SFC":
for transition in pou.gettransitionList():
pou_infos["values"].append({"name" : transition.getname(),
"elmt_type" : "TRANSITION", "type" : ITEM_TRANSITION,
"tagname" : self.ComputePouActionName(pou.getname(), transition.getname()),
"values" : []})
for action in pou.getactionList():
pou_infos["values"].append({"name": action.getname(),
"elmt_type" : "ACTION", "type": ITEM_ACTION,
"tagname" : self.ComputePouActionName(pou.getname(), action.getname()),
"values" : []})
if pou.interface:
# Extract variables from every varLists
for type, varlist in pou.getvars():
infos = VAR_CLASS_INFOS.get(type, None)
if infos is not None:
current_var_class = infos[1]
else:
current_var_class = ITEM_VAR_LOCAL
for variable in varlist.getvariable():
vartype_content = variable.gettype().getcontent()
if vartype_content["name"] == "derived":
var_infos = self.GetPouTopology(variable.getname(), vartype_content["value"].getname())
if var_infos is not None:
pou_infos["values"].append(var_infos)
elif vartype_content["name"] in ["string", "wstring"]:
pou_infos["values"].append({"name" : variable.getname(),
"elmt_type" : vartype_content["name"].upper(),
"type" : current_var_class, "values" : []})
else:
pou_infos["values"].append({"name" : variable.getname(),
"elmt_type" : vartype_content["name"],
"type" : current_var_class, "values" : []})
return pou_infos
block_infos = self.GetBlockType(type, debug = debug)
if block_infos is not None:
if block_infos["type"] == "function":
return None
elif block_infos["type"] == "program":
pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_PROGRAM, "values" : []}
else:
pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_FUNCTIONBLOCK, "values" : []}
for varname, vartype, varmodifier in block_infos["inputs"]:
pou_infos["values"].append({"name" : varname, "elmt_type" : vartype, "type" : ITEM_VAR_INPUT, "values" : []})
for varname, vartype, varmodifier in block_infos["outputs"]:
pou_infos["values"].append({"name" : varname, "elmt_type" : vartype, "type" : ITEM_VAR_INPUT, "values" : []})
return pou_infos
if type in self.GetDataTypes(debug = debug):
if global_var:
return {"name" : name, "elmt_type" : type, "type" : ITEM_VAR_GLOBAL, "values" : []}
else:
return {"name" : name, "elmt_type" : type, "type" : ITEM_VAR_LOCAL, "values" : []}
return None
# Return if data type given by name is used by another data type or pou
def DataTypeIsUsed(self, name, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.ElementIsUsed(name) or project.DataTypeIsDerived(name)
return False
# Return if pou given by name is used by another pou
def PouIsUsed(self, name, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.ElementIsUsed(name)
return False
# Return if pou given by name is directly or undirectly used by the reference pou
def PouIsUsedBy(self, name, reference, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.ElementIsUsedBy(name, reference)
return False
def GenerateProgram(self, filepath=None):
errors = []
warnings = []
if self.Project is not None:
try:
self.ProgramChunks = GenerateCurrentProgram(self, self.Project, errors, warnings)
self.NextCompiledProject = self.Copy(self.Project)
program_text = "".join([item[0] for item in self.ProgramChunks])
if filepath is not None:
programfile = open(filepath, "w")
programfile.write(program_text)
programfile.close()
self.ProgramFilePath = filepath
return program_text, errors, warnings
except PLCGenException, e:
errors.append(e.message)
else:
errors.append("No project opened")
return "", errors, warnings
def DebugAvailable(self):
return self.CurrentCompiledProject is not None
def ProgramTransferred(self):
self.CurrentCompiledProject = self.NextCompiledProject
def GetChunkInfos(self, from_location, to_location):
row = self.ProgramOffset + 1
col = 1
infos = []
for chunk, chunk_infos in self.ProgramChunks:
lines = chunk.split("\n")
if len(lines) > 1:
next_row = row + len(lines) - 1
next_col = len(lines[-1]) + 1
else:
next_row = row
next_col = col + len(chunk)
if (next_row > from_location[0] or next_row == from_location[0] and next_col >= from_location[1]) and len(chunk_infos) > 0:
infos.append((chunk_infos, (row, col)))
if next_row == to_location[0] and next_col > to_location[1] or next_row > to_location[0]:
return infos
row, col = next_row, next_col
return infos
#-------------------------------------------------------------------------------
# Project Pous management functions
#-------------------------------------------------------------------------------
# Add a Data Type to Project
def ProjectAddDataType(self, datatype_name):
if self.Project is not None:
# Add the datatype to project
self.Project.appenddataType(datatype_name)
self.BufferProject()
# Remove a Data Type from project
def ProjectRemoveDataType(self, datatype_name):
if self.Project is not None:
self.Project.removedataType(datatype_name)
self.BufferProject()
# Add a Pou to Project
def ProjectAddPou(self, pou_name, pou_type, body_type):
if self.Project is not None:
# Add the pou to project
self.Project.appendpou(pou_name, pou_type, body_type)
if pou_type == "function":
self.SetPouInterfaceReturnType(pou_name, "BOOL")
self.BufferProject()
def ProjectChangePouType(self, name, pou_type):
if self.Project is not None:
pou = self.Project.getpou(name)
if pou is not None:
pou.setpouType(pou_type)
self.Project.RefreshCustomBlockTypes()
self.BufferProject()
def GetPouXml(self, pou_name):
if self.Project is not None:
pou = self.Project.getpou(pou_name)
if pou is not None:
return pou.generateXMLText('pou', 0)
return None
def PastePou(self, pou_type, pou_xml):
'''
Adds the POU defined by 'pou_xml' to the current project with type 'pou_type'
'''
try:
tree = minidom.parseString(pou_xml)
root = tree.childNodes[0]
except:
return _("Couldn't paste non-POU object.")
if root.nodeName == "pou":
new_pou = plcopen.pous_pou()
new_pou.loadXMLTree(root)
name = new_pou.getname()
orig_type = new_pou.getpouType()
# prevent violations of POU content restrictions:
# function blocks cannot be pasted as functions,
# programs cannot be pasted as functions or function blocks
if orig_type == 'functionBlock' and pou_type == 'function' or \
orig_type == 'program' and pou_type in ['function', 'functionBlock']:
return _('''%s "%s" can't be pasted as a %s.''') % (orig_type, name, pou_type)
idx = 0
new_name = name
while self.Project.getpou(new_name):
# a POU with that name already exists.
# make a new name and test if a POU with that name exists.
# append an incrementing numeric suffix to the POU name.
idx += 1
new_name = "%s%d" % (name, idx)
# we've found a name that does not already exist, use it
new_pou.setname(new_name)
new_pou.setpouType(pou_type)
self.Project.insertpou(-1, new_pou)
self.BufferProject()
else:
return _("Couldn't paste non-POU object.")
# Remove a Pou from project
def ProjectRemovePou(self, pou_name):
if self.Project is not None:
self.Project.removepou(pou_name)
self.BufferProject()
# Add a configuration to Project
def ProjectAddConfiguration(self, config_name):
if self.Project is not None:
self.Project.addconfiguration(config_name)
self.BufferProject()
# Remove a configuration from project
def ProjectRemoveConfiguration(self, config_name):
if self.Project is not None:
self.Project.removeconfiguration(config_name)
self.BufferProject()
# Add a resource to a configuration of the Project
def ProjectAddConfigurationResource(self, config_name, resource_name):
if self.Project is not None:
self.Project.addconfigurationResource(config_name, resource_name)
self.BufferProject()
# Remove a resource from a configuration of the project
def ProjectRemoveConfigurationResource(self, config_name, resource_name):
if self.Project is not None:
self.Project.removeconfigurationResource(config_name, resource_name)
self.BufferProject()
# Add a Transition to a Project Pou
def ProjectAddPouTransition(self, pou_name, transition_name, transition_type):
if self.Project is not None:
pou = self.Project.getpou(pou_name)
if pou is not None:
pou.addtransition(transition_name, transition_type)
self.BufferProject()
# Remove a Transition from a Project Pou
def ProjectRemovePouTransition(self, pou_name, transition_name):
# Search if the pou removed is currently opened
if self.Project is not None:
pou = self.Project.getpou(pou_name)
if pou is not None:
pou.removetransition(transition_name)
self.BufferProject()
# Add an Action to a Project Pou
def ProjectAddPouAction(self, pou_name, action_name, action_type):
if self.Project is not None:
pou = self.Project.getpou(pou_name)
if pou is not None:
pou.addaction(action_name, action_type)
self.BufferProject()
# Remove an Action from a Project Pou
def ProjectRemovePouAction(self, pou_name, action_name):
# Search if the pou removed is currently opened
if self.Project is not None:
pou = self.Project.getpou(pou_name)
if pou is not None:
pou.removeaction(action_name)
self.BufferProject()
# Change the name of a pou
def ChangeDataTypeName(self, old_name, new_name):
if self.Project is not None:
# Found the pou corresponding to old name and change its name to new name
datatype = self.Project.getdataType(old_name)
if datatype is not None:
datatype.setname(new_name)
self.Project.updateElementName(old_name, new_name)
self.Project.RefreshElementUsingTree()
self.Project.RefreshDataTypeHierarchy()
self.BufferProject()
# Change the name of a pou
def ChangePouName(self, old_name, new_name):
if self.Project is not None:
# Found the pou corresponding to old name and change its name to new name
pou = self.Project.getpou(old_name)
if pou is not None:
pou.setname(new_name)
self.Project.updateElementName(old_name, new_name)
self.Project.RefreshElementUsingTree()
self.Project.RefreshCustomBlockTypes()
self.BufferProject()
# Change the name of a pou transition
def ChangePouTransitionName(self, pou_name, old_name, new_name):
if self.Project is not None:
# Found the pou transition corresponding to old name and change its name to new name
pou = self.Project.getpou(pou_name)
if pou is not None:
transition = pou.gettransition(old_name)
if transition is not None:
transition.setname(new_name)
pou.updateElementName(old_name, new_name)
self.BufferProject()
# Change the name of a pou action
def ChangePouActionName(self, pou_name, old_name, new_name):
if self.Project is not None:
# Found the pou action corresponding to old name and change its name to new name
pou = self.Project.getpou(pou_name)
if pou is not None:
action = pou.getaction(old_name)
if action is not None:
action.setname(new_name)
pou.updateElementName(old_name, new_name)
self.BufferProject()
# Change the name of a pou variable
def ChangePouVariableName(self, pou_name, old_name, new_name):
if self.Project is not None:
# Found the pou action corresponding to old name and change its name to new name
pou = self.Project.getpou(pou_name)
if pou is not None:
for type, varlist in pou.getvars():
for var in varlist.getvariable():
if var.getname() == old_name:
var.setname(new_name)
self.Project.RefreshCustomBlockTypes()
self.BufferProject()
# Change the name of a configuration
def ChangeConfigurationName(self, old_name, new_name):
if self.Project is not None:
# Found the configuration corresponding to old name and change its name to new name
configuration = self.Project.getconfiguration(old_name)
if configuration is not None:
configuration.setname(new_name)
self.BufferProject()
# Change the name of a configuration resource
def ChangeConfigurationResourceName(self, config_name, old_name, new_name):
if self.Project is not None:
# Found the resource corresponding to old name and change its name to new name
resource = self.Project.getconfigurationResource(config_name, old_name)
if resource is not None:
resource.setname(new_name)
self.BufferProject()
# Return the type of the pou given by its name
def GetPouType(self, name, debug = False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its type
pou = project.getpou(name)
if pou is not None:
return pou.getpouType()
return None
# Return pous with SFC language
def GetSFCPous(self, debug = False):
list = []
project = self.GetProject(debug)
if project is not None:
for pou in 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, debug = False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its body language
pou = project.getpou(name)
if pou is not None:
return pou.getbodyType()
return None
# Return the actions of a pou
def GetPouTransitions(self, pou_name, debug = False):
transitions = []
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its transitions if SFC
pou = project.getpou(pou_name)
if pou is not None and pou.getbodyType() == "SFC":
for transition in pou.gettransitionList():
transitions.append(transition.getname())
return transitions
# Return the body language of the transition given by its name
def GetTransitionBodyType(self, pou_name, pou_transition, debug = False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name
pou = project.getpou(pou_name)
if pou is not None:
# Found the pou transition correponding to name and return its body language
transition = pou.gettransition(pou_transition)
if transition is not None:
return transition.getbodyType()
return None
# Return the actions of a pou
def GetPouActions(self, pou_name, debug = False):
actions = []
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its actions if SFC
pou = project.getpou(pou_name)
if pou.getbodyType() == "SFC":
for action in pou.getactionList():
actions.append(action.getname())
return actions
# Return the body language of the pou given by its name
def GetActionBodyType(self, pou_name, pou_action, debug = False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its body language
pou = project.getpou(pou_name)
if pou is not None:
action = pou.getaction(pou_action)
if action is not None:
return action.getbodyType()
return None
# Extract varlists from a list of vars
def ExtractVarLists(self, vars):
varlist_list = []
current_varlist = None
current_type = None
for var in vars:
next_type = (var["Class"],
var["Option"],
var["Location"] in ["", None] or
# When declaring globals, located
# and not located variables are
# in the same declaration block
var["Class"] == "Global")
if current_type != next_type:
current_type = next_type
infos = VAR_CLASS_INFOS.get(var["Class"], None)
if infos is not None:
current_varlist = infos[0]()
else:
current_varlist = plcopen.varList()
varlist_list.append((var["Class"], current_varlist))
if var["Option"] == "Constant":
current_varlist.setconstant(True)
elif var["Option"] == "Retain":
current_varlist.setretain(True)
elif var["Option"] == "Non-Retain":
current_varlist.setnonretain(True)
# Create variable and change its properties
tempvar = plcopen.varListPlain_variable()
tempvar.setname(var["Name"])
var_type = plcopen.dataType()
if isinstance(var["Type"], TupleType):
if var["Type"][0] == "array":
array_type, base_type_name, dimensions = var["Type"]
array = plcopen.derivedTypes_array()
for i, dimension in enumerate(dimensions):
dimension_range = plcopen.rangeSigned()
dimension_range.setlower(dimension[0])
dimension_range.setupper(dimension[1])
if i == 0:
array.setdimension([dimension_range])
else:
array.appenddimension(dimension_range)
if base_type_name in self.GetBaseTypes():
if base_type_name == "STRING":
array.baseType.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
elif base_type_name == "WSTRING":
array.baseType.setcontent({"name" : "wstring", "value" : plcopen.wstring()})
else:
array.baseType.setcontent({"name" : base_type_name, "value" : None})
else:
derived_datatype = plcopen.derivedTypes_derived()
derived_datatype.setname(base_type_name)
array.baseType.setcontent({"name" : "derived", "value" : derived_datatype})
var_type.setcontent({"name" : "array", "value" : array})
elif var["Type"] in self.GetBaseTypes():
if var["Type"] == "STRING":
var_type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
elif var["Type"] == "WSTRING":
var_type.setcontent({"name" : "wstring", "value" : plcopen.elementaryTypes_wstring()})
else:
var_type.setcontent({"name" : var["Type"], "value" : None})
else:
derived_type = plcopen.derivedTypes_derived()
derived_type.setname(var["Type"])
var_type.setcontent({"name" : "derived", "value" : derived_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"])
else:
tempvar.setaddress(None)
if var['Documentation'] != "":
ft = plcopen.formattedText()
ft.settext(var['Documentation'])
tempvar.setdocumentation(ft)
# Add variable to varList
current_varlist.appendvariable(tempvar)
return varlist_list
def GetVariableDictionary(self, varlist, var):
'''
convert a PLC variable to the dictionary representation
returned by Get*Vars)
'''
tempvar = {"Name": var.getname()}
vartype_content = var.gettype().getcontent()
if vartype_content["name"] == "derived":
tempvar["Type"] = vartype_content["value"].getname()
elif vartype_content["name"] == "array":
dimensions = []
for dimension in vartype_content["value"].getdimension():
dimensions.append((dimension.getlower(), dimension.getupper()))
base_type = vartype_content["value"].baseType.getcontent()
if base_type["value"] is None:
base_type_name = base_type["name"]
else:
base_type_name = base_type["value"].getname()
tempvar["Type"] = ("array", base_type_name, dimensions)
elif vartype_content["name"] in ["string", "wstring"]:
tempvar["Type"] = vartype_content["name"].upper()
else:
tempvar["Type"] = vartype_content["name"]
tempvar["Edit"] = True
initial = var.getinitialValue()
if initial:
tempvar["Initial Value"] = initial.getvalue()
else:
tempvar["Initial Value"] = ""
address = var.getaddress()
if address:
tempvar["Location"] = address
else:
tempvar["Location"] = ""
if varlist.getconstant():
tempvar["Option"] = "Constant"
elif varlist.getretain():
tempvar["Option"] = "Retain"
elif varlist.getnonretain():
tempvar["Option"] = "Non-Retain"
else:
tempvar["Option"] = ""
doc = var.getdocumentation()
if doc:
tempvar["Documentation"] = doc.gettext()
else:
tempvar["Documentation"] = ""
return tempvar
# Replace the configuration globalvars by those given
def SetConfigurationGlobalVars(self, name, vars):
if self.Project is not None:
# Found the configuration corresponding to name
configuration = self.Project.getconfiguration(name)
if configuration is not None:
# Set configuration global vars
configuration.setglobalVars([])
for vartype, varlist in self.ExtractVarLists(vars):
configuration.globalVars.append(varlist)
# Return the configuration globalvars
def GetConfigurationGlobalVars(self, name, debug = False):
vars = []
project = self.GetProject(debug)
if project is not None:
# Found the configuration corresponding to name
configuration = project.getconfiguration(name)
if configuration is not None:
# Extract variables from every varLists
for varlist in configuration.getglobalVars():
for var in varlist.getvariable():
tempvar = self.GetVariableDictionary(varlist, var)
tempvar["Class"] = "Global"
vars.append(tempvar)
return vars
# Replace the resource globalvars by those given
def SetConfigurationResourceGlobalVars(self, config_name, name, vars):
if self.Project is not None:
# Found the resource corresponding to name
resource = self.Project.getconfigurationResource(config_name, name)
# Set resource global vars
if resource is not None:
resource.setglobalVars([])
for vartype, varlist in self.ExtractVarLists(vars):
resource.globalVars.append(varlist)
# Return the resource globalvars
def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False):
vars = []
project = self.GetProject(debug)
if project is not None:
# Found the resource corresponding to name
resource = project.getconfigurationResource(config_name, name)
if resource:
# Extract variables from every varLists
for varlist in resource.getglobalVars():
for var in varlist.getvariable():
tempvar = self.GetVariableDictionary(varlist, var)
tempvar["Class"] = "Global"
vars.append(tempvar)
return vars
# Recursively generate element name tree for a structured variable
def GenerateVarTree(self, typename, debug = False):
project = self.GetProject(debug)
if project is not None:
blocktype = self.GetBlockType(typename, debug = debug)
if blocktype is not None:
tree = []
for var_name, var_type, var_modifier in blocktype["inputs"] + blocktype["outputs"]:
tree.append((var_name, var_type, self.GenerateVarTree(var_type, debug)))
return tree, []
datatype = project.getdataType(typename)
if datatype is not None:
tree = []
basetype_content = datatype.baseType.getcontent()
if basetype_content["name"] == "derived":
return self.GenerateVarTree(basetype_content["value"].getname())
elif basetype_content["name"] == "array":
dimensions = []
base_type = basetype_content["value"].baseType.getcontent()
if base_type["name"] == "derived":
tree = self.GenerateVarTree(base_type["value"].getname())
if len(tree[1]) == 0:
tree = tree[0]
for dimension in basetype_content["value"].getdimension():
dimensions.append((dimension.getlower(), dimension.getupper()))
return tree, dimensions
elif basetype_content["name"] == "struct":
for element in basetype_content["value"].getvariable():
element_type = element.type.getcontent()
if element_type["name"] == "derived":
tree.append((element.getname(), element_type["value"].getname(), self.GenerateVarTree(element_type["value"].getname())))
else:
tree.append((element.getname(), element_type["name"], ([], [])))
return tree, []
return [], []
# Return the interface for the given pou
def GetPouInterfaceVars(self, pou, debug = False):
vars = []
# Verify that the pou has an interface
if pou.interface is not None:
# Extract variables from every varLists
for type, varlist in pou.getvars():
for var in varlist.getvariable():
tempvar = self.GetVariableDictionary(varlist, var)
tempvar["Class"] = type
tempvar["Tree"] = ([], [])
vartype_content = var.gettype().getcontent()
if vartype_content["name"] == "derived":
tempvar["Edit"] = not pou.hasblock(tempvar["Name"])
tempvar["Tree"] = self.GenerateVarTree(tempvar["Type"], debug)
vars.append(tempvar)
return vars
# Replace the Pou interface by the one given
def SetPouInterfaceVars(self, name, vars):
if self.Project is not None:
# Found the pou corresponding to name and add interface if there isn't one yet
pou = self.Project.getpou(name)
if pou is not None:
if pou.interface is None:
pou.interface = plcopen.pou_interface()
# Set Pou interface
pou.setvars(self.ExtractVarLists(vars))
self.Project.RefreshElementUsingTree()
self.Project.RefreshCustomBlockTypes()
# Replace the return type of the pou given by its name (only for functions)
def SetPouInterfaceReturnType(self, name, type):
if self.Project is not None:
pou = self.Project.getpou(name)
if pou is not None:
if pou.interface is None:
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
if type in self.GetBaseTypes():
if type == "STRING":
return_type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
elif type == "WSTRING":
return_type.setcontent({"name" : "wstring", "value" : plcopen.elementaryTypes_wstring()})
else:
return_type.setcontent({"name" : type, "value" : None})
else:
derived_type = plcopen.derivedTypes_derived()
derived_type.setname(type)
return_type.setcontent({"name" : "derived", "value" : derived_type})
self.Project.RefreshElementUsingTree()
self.Project.RefreshCustomBlockTypes()
def UpdateProjectUsedPous(self, old_name, new_name):
if self.Project:
self.Project.updateElementName(old_name, new_name)
def UpdateEditedElementUsedVariable(self, tagname, old_name, new_name):
pou = self.GetEditedElement(tagname)
if pou:
pou.updateElementName(old_name, new_name)
# Return the return type of the pou given by its name
def GetPouInterfaceReturnTypeByName(self, name):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return the return type
pou = project.getpou(name)
if pou is not None:
return self.GetPouInterfaceReturnType(pou)
return False
# Return the return type of the given pou
def GetPouInterfaceReturnType(self, pou):
# Verify that the pou has an interface
if pou.interface is not None:
# Return the return type if there is one
return_type = pou.interface.getreturnType()
if return_type:
returntype_content = return_type.getcontent()
if returntype_content["name"] == "derived":
return returntype_content["value"].getname()
elif returntype_content["name"] in ["string", "wstring"]:
return returntype_content["name"].upper()
else:
return returntype_content["name"]
return None
# Function that add a new plugin to the plugin list
def AddPluginBlockList(self, blocklist):
self.PluginTypes.extend(blocklist)
# Function that clear the plugin list
def ClearPluginTypes(self):
for i in xrange(len(self.PluginTypes)):
self.PluginTypes.pop(0)
def GetVariableLocationTree(self):
return []
# Function that returns the block definition associated to the block type given
def GetBlockType(self, type, inputs = None, debug = False):
result_blocktype = None
for category in BlockTypes + self.PluginTypes:
for blocktype in category["list"]:
if blocktype["name"] == type:
if inputs is not None and inputs != "undefined":
block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
if reduce(lambda x, y: x and y, map(lambda x: x[0] == "ANY" or self.IsOfType(*x), zip(inputs, block_inputs))):
return blocktype
else:
if result_blocktype is not None:
if inputs == "undefined":
return None
else:
result_blocktype["inputs"] = [(i[0], "ANY", i[2]) for i in result_blocktype["inputs"]]
result_blocktype["outputs"] = [(o[0], "ANY", o[2]) for o in result_blocktype["outputs"]]
return result_blocktype
result_blocktype = blocktype
if result_blocktype is not None:
return result_blocktype
project = self.GetProject(debug)
if project is not None:
return project.GetCustomBlockType(type, inputs)
return None
# Return Block types checking for recursion
def GetBlockTypes(self, tagname = "", debug = False):
type = None
words = tagname.split("::")
if self.Project:
name = ""
if words[0] in ["P","T","A"]:
name = words[1]
type = self.GetPouType(name, debug)
if type == "function" or words[0] == "T":
blocktypes = []
for category in BlockTypes + self.PluginTypes:
cat = {"name" : category["name"], "list" : []}
for block in category["list"]:
if block["type"] == "function":
cat["list"].append(block)
if len(cat["list"]) > 0:
blocktypes.append(cat)
else:
blocktypes = [category for category in BlockTypes + self.PluginTypes]
project = self.GetProject(debug)
if project is not None:
blocktypes.append({"name" : USER_DEFINED_POUS, "list": project.GetCustomBlockTypes(name, type == "function" or words[0] == "T")})
return blocktypes
# Return Function Block types checking for recursion
def GetFunctionBlockTypes(self, tagname = "", debug = False):
blocktypes = []
for category in BlockTypes + self.PluginTypes:
for block in category["list"]:
if block["type"] == "functionBlock":
blocktypes.append(block["name"])
project = self.GetProject(debug)
if project is not None:
name = ""
words = tagname.split("::")
if words[0] in ["P","T","A"]:
name = words[1]
blocktypes.extend(project.GetCustomFunctionBlockTypes(name))
return blocktypes
# Return Block types checking for recursion
def GetBlockResource(self, debug = False):
blocktypes = []
for category in BlockTypes[:-1]:
for blocktype in category["list"]:
if blocktype["type"] == "program":
blocktypes.append(blocktype["name"])
project = self.GetProject(debug)
if project is not None:
blocktypes.extend(project.GetCustomBlockResource())
return blocktypes
# Return Data Types checking for recursion
def GetDataTypes(self, tagname = "", basetypes = True, debug = False):
if basetypes:
datatypes = self.GetBaseTypes()
else:
datatypes = []
project = self.GetProject(debug)
if project is not None:
name = ""
words = tagname.split("::")
if words[0] in ["D"]:
name = words[1]
datatypes.extend(project.GetCustomDataTypes(name))
return datatypes
# Return Base Type of given possible derived type
def GetBaseType(self, type, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.GetBaseType(type)
return None
def GetBaseTypes(self):
'''
return the list of datatypes defined in IEC 61131-3.
TypeHierarchy_list has a rough order to it (e.g. SINT, INT, DINT, ...),
which makes it easy for a user to find a type in a menu.
'''
return [x for x,y in TypeHierarchy_list if not x.startswith("ANY")]
def IsOfType(self, type, reference, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.IsOfType(type, reference)
elif reference is None:
return True
elif type == reference:
return True
else:
if type in TypeHierarchy:
return self.IsOfType(TypeHierarchy[type], reference)
return None
def IsEndType(self, type):
if type is not None:
return not type.startswith("ANY")
return True
def GetDataTypeRange(self, type, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.GetDataTypeRange(type)
elif type in DataTypeRange:
return DataTypeRange[type]
return None
# Return Subrange types
def GetSubrangeBaseTypes(self, exclude, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.GetSubrangeBaseTypes(exclude)
return []
# Return Enumerated Values
def GetEnumeratedDataValues(self, debug = False):
project = self.GetProject(debug)
if project is not None:
return project.GetEnumeratedDataTypeValues()
return []
#-------------------------------------------------------------------------------
# Project Element tag name computation functions
#-------------------------------------------------------------------------------
# Compute a data type name
def ComputeDataTypeName(self, datatype):
return "D::%s" % datatype
# Compute a pou name
def ComputePouName(self, pou):
return "P::%s" % pou
# 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 ComputeConfigurationName(self, config):
return "C::%s" % config
# Compute a pou name
def ComputeConfigurationResourceName(self, config, resource):
return "R::%s::%s" % (config, resource)
def GetElementType(self, tagname):
words = tagname.split("::")
return {"D" : ITEM_DATATYPE, "P" : ITEM_POU,
"T" : ITEM_TRANSITION, "A" : ITEM_ACTION,
"C" : ITEM_CONFIGURATION, "R" : ITEM_RESOURCE}[words[0]]
#-------------------------------------------------------------------------------
# Project opened Data types management functions
#-------------------------------------------------------------------------------
# Return the data type informations
def GetDataTypeInfos(self, tagname, debug = False):
project = self.GetProject(debug)
if project is not None:
words = tagname.split("::")
if words[0] == "D":
infos = {}
datatype = project.getdataType(words[1])
basetype_content = datatype.baseType.getcontent()
if basetype_content["value"] is None:
infos["type"] = "Directly"
infos["base_type"] = basetype_content["name"]
elif basetype_content["name"] == "derived":
infos["type"] = "Directly"
infos["base_type"] = basetype_content["value"].getname()
elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]:
infos["type"] = "Subrange"
infos["min"] = basetype_content["value"].range.getlower()
infos["max"] = basetype_content["value"].range.getupper()
base_type = basetype_content["value"].baseType.getcontent()
if base_type["value"] is None:
infos["base_type"] = base_type["name"]
else:
infos["base_type"] = base_type["value"].getname()
elif basetype_content["name"] == "enum":
infos["type"] = "Enumerated"
infos["values"] = []
for value in basetype_content["value"].values.getvalue():
infos["values"].append(value.getname())
elif basetype_content["name"] == "array":
infos["type"] = "Array"
infos["dimensions"] = []
for dimension in basetype_content["value"].getdimension():
infos["dimensions"].append((dimension.getlower(), dimension.getupper()))
base_type = basetype_content["value"].baseType.getcontent()
if base_type["value"] is None:
infos["base_type"] = base_type["name"]
else:
infos["base_type"] = base_type["value"].getname()
elif basetype_content["name"] == "struct":
infos["type"] = "Structure"
infos["elements"] = []
for element in basetype_content["value"].getvariable():
element_infos = {}
element_infos["Name"] = element.getname()
element_type = element.type.getcontent()
if element_type["value"] is None:
element_infos["Type"] = element_type["name"]
else:
element_infos["Type"] = element_type["value"].getname()
if element.initialValue is not None:
element_infos["Initial Value"] = str(element.initialValue.getvalue())
else:
element_infos["Initial Value"] = ""
infos["elements"].append(element_infos)
if datatype.initialValue is not None:
infos["initial"] = str(datatype.initialValue.getvalue())
else:
infos["initial"] = ""
return infos
return None
# Change the data type informations
def SetDataTypeInfos(self, tagname, infos):
words = tagname.split("::")
if self.Project is not None and words[0] == "D":
datatype = self.Project.getdataType(words[1])
if infos["type"] == "Directly":
if infos["base_type"] in self.GetBaseTypes():
if infos["base_type"] == "STRING":
datatype.baseType.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
elif infos["base_type"] == "WSTRING":
datatype.baseType.setcontent({"name" : "wstring", "value" : plcopen.elementaryTypes_wstring()})
else:
datatype.baseType.setcontent({"name" : infos["base_type"], "value" : None})
else:
derived_datatype = plcopen.derivedTypes_derived()
derived_datatype.setname(infos["base_type"])
datatype.baseType.setcontent({"name" : "derived", "value" : derived_datatype})
elif infos["type"] == "Subrange":
if infos["base_type"] in GetSubTypes("ANY_UINT"):
subrange = plcopen.derivedTypes_subrangeUnsigned()
datatype.baseType.setcontent({"name" : "subrangeUnsigned", "value" : subrange})
else:
subrange = plcopen.derivedTypes_subrangeSigned()
datatype.baseType.setcontent({"name" : "subrangeSigned", "value" : subrange})
subrange.range.setlower(infos["min"])
subrange.range.setupper(infos["max"])
if infos["base_type"] in self.GetBaseTypes():
subrange.baseType.setcontent({"name" : infos["base_type"], "value" : None})
else:
derived_datatype = plcopen.derivedTypes_derived()
derived_datatype.setname(infos["base_type"])
subrange.baseType.setcontent({"name" : "derived", "value" : derived_datatype})
elif infos["type"] == "Enumerated":
enumerated = plcopen.derivedTypes_enum()
for i, enum_value in enumerate(infos["values"]):
value = plcopen.values_value()
value.setname(enum_value)
if i == 0:
enumerated.values.setvalue([value])
else:
enumerated.values.appendvalue(value)
datatype.baseType.setcontent({"name" : "enum", "value" : enumerated})
elif infos["type"] == "Array":
array = plcopen.derivedTypes_array()
for i, dimension in enumerate(infos["dimensions"]):
dimension_range = plcopen.rangeSigned()
dimension_range.setlower(dimension[0])
dimension_range.setupper(dimension[1])
if i == 0:
array.setdimension([dimension_range])
else:
array.appenddimension(dimension_range)
if infos["base_type"] in self.GetBaseTypes():
if infos["base_type"] == "STRING":
array.baseType.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
elif infos["base_type"] == "WSTRING":
array.baseType.setcontent({"name" : "wstring", "value" : plcopen.wstring()})
else:
array.baseType.setcontent({"name" : infos["base_type"], "value" : None})
else:
derived_datatype = plcopen.derivedTypes_derived()
derived_datatype.setname(infos["base_type"])
array.baseType.setcontent({"name" : "derived", "value" : derived_datatype})
datatype.baseType.setcontent({"name" : "array", "value" : array})
elif infos["type"] == "Structure":
struct = plcopen.varListPlain()
for i, element_infos in enumerate(infos["elements"]):
element = plcopen.varListPlain_variable()
element.setname(element_infos["Name"])
if element_infos["Type"] in self.GetBaseTypes():
if element_infos["Type"] == "STRING":
element.type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
elif element_infos["Type"] == "WSTRING":
element.type.setcontent({"name" : "wstring", "value" : plcopen.wstring()})
else:
element.type.setcontent({"name" : element_infos["Type"], "value" : None})
else:
derived_datatype = plcopen.derivedTypes_derived()
derived_datatype.setname(element_infos["Type"])
element.type.setcontent({"name" : "derived", "value" : derived_datatype})
if element_infos["Initial Value"] != "":
value = plcopen.value()
value.setvalue(element_infos["Initial Value"])
element.setinitialValue(value)
if i == 0:
struct.setvariable([element])
else:
struct.appendvariable(element)
datatype.baseType.setcontent({"name" : "struct", "value" : struct})
if infos["initial"] != "":
if datatype.initialValue is None:
datatype.initialValue = plcopen.value()
datatype.initialValue.setvalue(infos["initial"])
else:
datatype.initialValue = None
self.Project.RefreshDataTypeHierarchy()
self.Project.RefreshElementUsingTree()
self.BufferProject()
#-------------------------------------------------------------------------------
# Project opened Pous management functions
#-------------------------------------------------------------------------------
# Return edited element
def GetEditedElement(self, tagname, debug = False):
project = self.GetProject(debug)
if project is not None:
words = tagname.split("::")
if words[0] == "D":
return project.getdataType(words[1])
elif words[0] == "P":
return project.getpou(words[1])
elif words[0] in ['T', 'A']:
pou = project.getpou(words[1])
if pou is not None:
if words[0] == 'T':
return pou.gettransition(words[2])
elif words[0] == 'A':
return pou.getaction(words[2])
elif words[0] == 'C':
return project.getconfiguration(words[1])
elif words[0] == 'R':
return project.getconfigurationResource(words[1], words[2])
return None
# Return edited element name
def GetEditedElementName(self, tagname):
words = tagname.split("::")
if words[0] in ["P","C","D"]:
return words[1]
else:
return words[2]
return None
# Return edited element name and type
def GetEditedElementType(self, tagname, debug = False):
words = tagname.split("::")
if words[0] in ["P","T","A"]:
return words[1], self.GetPouType(words[1], debug)
return None, None
# Return language in which edited element is written
def GetEditedElementBodyType(self, tagname, debug = False):
words = tagname.split("::")
if words[0] == "P":
return self.GetPouBodyType(words[1], debug)
elif words[0] == 'T':
return self.GetTransitionBodyType(words[1], words[2], debug)
elif words[0] == 'A':
return self.GetActionBodyType(words[1], words[2], debug)
return None
# Return the edited element variables
def GetEditedElementInterfaceVars(self, tagname, debug = False):
words = tagname.split("::")
if words[0] in ["P","T","A"]:
project = self.GetProject(debug)
if project is not None:
pou = project.getpou(words[1])
if pou is not None:
return self.GetPouInterfaceVars(pou, debug)
return []
# Return the edited element return type
def GetEditedElementInterfaceReturnType(self, tagname, debug = False):
words = tagname.split("::")
if words[0] == "P":
project = self.GetProject(debug)
if project is not None:
pou = self.Project.getpou(words[1])
if pou is not None:
return self.GetPouInterfaceReturnType(pou)
elif words[0] == 'T':
return "BOOL"
return None
# Change the edited element text
def SetEditedElementText(self, tagname, text):
if self.Project is not None:
element = self.GetEditedElement(tagname)
if element is not None:
element.settext(text)
self.Project.RefreshElementUsingTree()
# Return the edited element text
def GetEditedElementText(self, tagname, debug = False):
element = self.GetEditedElement(tagname, debug)
if element is not None:
return element.gettext()
return ""
# Return the edited element transitions
def GetEditedElementTransitions(self, tagname, debug = False):
pou = self.GetEditedElement(tagname, debug)
if pou is not None and pou.getbodyType() == "SFC":
transitions = []
for transition in pou.gettransitionList():
transitions.append(transition.getname())
return transitions
return []
# Return edited element transitions
def GetEditedElementActions(self, tagname, debug = False):
pou = self.GetEditedElement(tagname, debug)
if pou is not None and pou.getbodyType() == "SFC":
actions = []
for action in pou.getactionList():
actions.append(action.getname())
return actions
return []
# Return the names of the pou elements
def GetEditedElementVariables(self, tagname, debug = False):
words = tagname.split("::")
if words[0] in ["P","T","A"]:
return self.GetProjectPouVariables(words[1], debug)
return []
def GetEditedElementCopy(self, tagname, debug = False):
element = self.GetEditedElement(tagname, debug)
if element is not None:
name = element.__class__.__name__
return element.generateXMLText(name.split("_")[-1], 0)
return ""
def GetEditedElementInstancesCopy(self, tagname, blocks_id = None, wires = None, debug = False):
element = self.GetEditedElement(tagname, debug)
text = ""
if element is not None:
wires = dict([(wire, True) for wire in wires if wire[0] in blocks_id and wire[1] in blocks_id])
for id in blocks_id:
instance = element.getinstance(id)
if instance is not None:
instance_copy = self.Copy(instance)
instance_copy.filterConnections(wires)
name = instance_copy.__class__.__name__
text += instance_copy.generateXMLText(name.split("_")[-1], 0)
return text
def GenerateNewName(self, tagname, name, format, exclude={}, debug=False):
names = exclude.copy()
names.update(dict([(varname.upper(), True) for varname in self.GetEditedElementVariables(tagname, debug)]))
element = self.GetEditedElement(tagname, debug)
if element is not None:
for instance in element.getinstances():
if isinstance(instance, (plcopen.sfcObjects_step, plcopen.commonObjects_connector, plcopen.commonObjects_continuation)):
names[instance.getname()] = True
i = 1
while names.get(name.upper(), False):
name = (format%i)
i += 1
return name
CheckPasteCompatibility = {"SFC": lambda name: True,
"LD": lambda name: not name.startswith("sfcObjects"),
"FBD": lambda name: name.startswith("fbdObjects") or name.startswith("commonObjects")}
def PasteEditedElementInstances(self, tagname, text, new_pos, middle=False, debug=False):
element = self.GetEditedElement(tagname, debug)
element_name, element_type = self.GetEditedElementType(tagname, debug)
if element is not None:
bodytype = element.getbodyType()
# Get edited element type scaling
scaling = None
project = self.GetProject(debug)
if project is not None:
properties = project.getcontentHeader()
scaling = properties["scaling"][bodytype]
# Get ids already by all the instances in edited element
used_id = dict([(instance.getlocalId(), True) for instance in element.getinstances()])
new_id = {}
text = "<paste>%s</paste>"%text
try:
tree = minidom.parseString(text)
except:
return _("Invalid plcopen element(s)!!!")
instances = []
exclude = {}
for root in tree.childNodes:
if root.nodeType == tree.ELEMENT_NODE and root.nodeName == "paste":
for child in root.childNodes:
if child.nodeType == tree.ELEMENT_NODE:
if not child.nodeName in plcopen.ElementNameToClass:
return _("\"%s\" element can't be pasted here!!!")%child.nodeName
classname = plcopen.ElementNameToClass[child.nodeName]
if not self.CheckPasteCompatibility[bodytype](classname):
return _("\"%s\" element can't be pasted here!!!")%child.nodeName
classobj = getattr(plcopen, classname, None)
if classobj is not None:
instance = classobj()
instance.loadXMLTree(child)
if child.nodeName == "block":
blockname = instance.getinstanceName()
if blockname is not None:
blocktype = instance.gettypeName()
if element_type == "function":
return _("FunctionBlock \"%s\" can't be pasted in a Function!!!")%blocktype
blockname = self.GenerateNewName(tagname, blockname, "Block%d", debug=debug)
exclude[blockname] = True
instance.setinstanceName(blockname)
self.AddEditedElementPouVar(tagname, blocktype, blockname)
elif child.nodeName == "step":
stepname = self.GenerateNewName(tagname, instance.getname(), "Step%d", exclude, debug)
exclude[stepname] = True
instance.setname(stepname)
localid = instance.getlocalId()
if not used_id.has_key(localid):
new_id[localid] = True
instances.append((child.nodeName, instance))
if len(instances) == 0:
return _("Invalid plcopen element(s)!!!")
idx = 1
translate_id = {}
bbox = plcopen.rect()
for name, instance in instances:
localId = instance.getlocalId()
bbox.union(instance.getBoundingBox())
if used_id.has_key(localId):
while used_id.has_key(idx) or new_id.has_key(idx):
idx += 1
new_id[idx] = True
instance.setlocalId(idx)
translate_id[localId] = idx
x, y, width, height = bbox.bounding_box()
if middle:
new_pos[0] -= width / 2
new_pos[1] -= height / 2
else:
new_pos = map(lambda x: x + 30, new_pos)
if scaling[0] != 0 and scaling[1] != 0:
min_pos = map(lambda x: 30 / x, scaling)
minx = round(min_pos[0])
if int(min_pos[0]) == round(min_pos[0]):
minx += 1
miny = round(min_pos[1])
if int(min_pos[1]) == round(min_pos[1]):
miny += 1
minx *= scaling[0]
miny *= scaling[1]
new_pos = (max(minx, round(new_pos[0] / scaling[0]) * scaling[0]),
max(miny, round(new_pos[1] / scaling[1]) * scaling[1]))
else:
new_pos = (max(30, new_pos[0]), max(30, new_pos[1]))
diff = (new_pos[0] - x, new_pos[1] - y)
connections = {}
for name, instance in instances:
connections.update(instance.updateConnectionsId(translate_id))
if getattr(instance, "setexecutionOrderId", None) is not None:
instance.setexecutionOrderId(0)
instance.translate(*diff)
element.addinstance(name, instance)
return new_id, connections
# Return the current pou editing informations
def GetEditedElementInstanceInfos(self, tagname, id = None, exclude = [], debug = False):
infos = {}
instance = None
element = self.GetEditedElement(tagname, debug)
if element is not None:
# if id is defined
if id is not None:
instance = element.getinstance(id)
else:
instance = element.getrandomInstance(exclude)
if instance is not None:
infos = instance.getinfos()
if infos["type"] in ["input", "output", "inout"]:
var_type = self.GetEditedElementVarValueType(tagname, infos["specific_values"]["name"], debug)
infos["specific_values"]["value_type"] = var_type
return infos
return None
def ClearEditedElementExecutionOrder(self, tagname):
element = self.GetEditedElement(tagname)
if element is not None:
element.resetexecutionOrder()
def ResetEditedElementExecutionOrder(self, tagname):
element = self.GetEditedElement(tagname)
if element is not None:
element.compileexecutionOrder()
# Return the variable type of the given pou
def GetEditedElementVarValueType(self, tagname, varname, debug = False):
project = self.GetProject(debug)
if project is not None:
words = tagname.split("::")
if words[0] in ["P","T","A"]:
pou = self.Project.getpou(words[1])
if pou is not None:
if words[0] == "T" and varname == words[2]:
return "BOOL"
if words[1] == varname:
return self.GetPouInterfaceReturnType(pou)
for type, varlist in pou.getvars():
for var in varlist.getvariable():
if var.getname() == varname:
vartype_content = var.gettype().getcontent()
if vartype_content["name"] == "derived":
return vartype_content["value"].getname()
elif vartype_content["name"] in ["string", "wstring"]:
return vartype_content["name"].upper()
else:
return vartype_content["name"]
return None
def SetConnectionWires(self, connection, connector):
wires = connector.GetWires()
idx = 0
for wire, handle in wires:
points = wire.GetPoints(handle != 0)
if handle == 0:
result = wire.GetConnectedInfos(-1)
else:
result = wire.GetConnectedInfos(0)
if result != None:
refLocalId, formalParameter = result
connections = connection.getconnections()
if connections is None or len(connection.getconnections()) <= idx:
connection.addconnection()
connection.setconnectionId(idx, refLocalId)
connection.setconnectionPoints(idx, points)
if formalParameter != "":
connection.setconnectionParameter(idx, formalParameter)
else:
connection.setconnectionParameter(idx, None)
idx += 1
def AddEditedElementPouVar(self, tagname, type, name, location="", description=""):
if self.Project is not None:
words = tagname.split("::")
if words[0] in ['P', 'T', 'A']:
pou = self.Project.getpou(words[1])
if pou is not None:
if pou.interface is None:
pou.interface = plcopen.pou_interface()
pou.addpouVar(type, name, location, description)
def ChangeEditedElementPouVar(self, tagname, old_type, old_name, new_type, new_name):
if self.Project is not None:
words = tagname.split("::")
if words[0] in ['P', 'T', 'A']:
pou = self.Project.getpou(words[1])
if pou is not None:
pou.changepouVar(old_type, old_name, new_type, new_name)
def RemoveEditedElementPouVar(self, tagname, type, name):
if self.Project is not None:
words = tagname.split("::")
if words[0] in ['P', 'T', 'A']:
pou = self.Project.getpou(words[1])
if pou is not None:
pou.removepouVar(type, name)
def AddEditedElementBlock(self, tagname, id, blocktype, blockname = None):
element = self.GetEditedElement(tagname)
if element is not None:
block = plcopen.fbdObjects_block()
block.setlocalId(id)
block.settypeName(blocktype)
blocktype_infos = self.GetBlockType(blocktype)
if blocktype_infos["type"] != "function" and blockname is not None:
block.setinstanceName(blockname)
self.AddEditedElementPouVar(tagname, blocktype, blockname)
element.addinstance("block", block)
self.Project.RefreshElementUsingTree()
def SetEditedElementBlockInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
block = element.getinstance(id)
if block is None:
return
old_name = block.getinstanceName()
old_type = block.gettypeName()
new_name = infos.get("name", old_name)
new_type = infos.get("type", old_type)
if new_type != old_type:
old_typeinfos = self.GetBlockType(old_type)
new_typeinfos = self.GetBlockType(new_type)
if old_typeinfos is None or new_typeinfos is None:
self.ChangeEditedElementPouVar(tagname, old_type, old_name, new_type, new_name)
elif new_typeinfos["type"] != old_typeinfos["type"]:
if new_typeinfos["type"] == "function":
self.RemoveEditedElementPouVar(tagname, old_type, old_name)
else:
self.AddEditedElementPouVar(tagname, new_type, new_name)
elif new_typeinfos["type"] != "function" and old_name != new_name:
self.ChangeEditedElementPouVar(tagname, old_type, old_name, new_type, new_name)
elif new_name != old_name:
self.ChangeEditedElementPouVar(tagname, old_type, old_name, new_type, new_name)
for param, value in infos.items():
if param == "name":
block.setinstanceName(value)
elif param == "type":
block.settypeName(value)
elif param == "executionOrder" and block.getexecutionOrderId() != value:
element.setelementExecutionOrder(block, 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.setedge(connector.GetEdge())
position = connector.GetRelPosition()
variable.connectionPointIn.setrelPositionXY(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.setedge(connector.GetEdge())
position = connector.GetRelPosition()
variable.addconnectionPointOut()
variable.connectionPointOut.setrelPositionXY(position.x, position.y)
block.outputVariables.appendvariable(variable)
self.Project.RefreshElementUsingTree()
def AddEditedElementVariable(self, tagname, id, type):
element = self.GetEditedElement(tagname)
if element is not None:
if type == INPUT:
name = "inVariable"
variable = plcopen.fbdObjects_inVariable()
elif type == OUTPUT:
name = "outVariable"
variable = plcopen.fbdObjects_outVariable()
elif type == INOUT:
name = "inOutVariable"
variable = plcopen.fbdObjects_inOutVariable()
variable.setlocalId(id)
element.addinstance(name, variable)
def SetEditedElementVariableInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
variable = element.getinstance(id)
if variable is None:
return
for param, value in infos.items():
if param == "name":
variable.setexpression(value)
elif param == "executionOrder" and variable.getexecutionOrderId() != value:
element.setelementExecutionOrder(variable, 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 len(value["outputs"]) > 0:
output = value["outputs"][0]
if len(value["inputs"]) > 0:
variable.setnegatedOut(output.IsNegated())
variable.setedgeOut(output.GetEdge())
else:
variable.setnegated(output.IsNegated())
variable.setedge(output.GetEdge())
position = output.GetRelPosition()
variable.addconnectionPointOut()
variable.connectionPointOut.setrelPositionXY(position.x, position.y)
if len(value["inputs"]) > 0:
input = value["inputs"][0]
if len(value["outputs"]) > 0:
variable.setnegatedIn(input.IsNegated())
variable.setedgeIn(input.GetEdge())
else:
variable.setnegated(input.IsNegated())
variable.setedge(input.GetEdge())
position = input.GetRelPosition()
variable.addconnectionPointIn()
variable.connectionPointIn.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(variable.connectionPointIn, input)
def AddEditedElementConnection(self, tagname, id, type):
element = self.GetEditedElement(tagname)
if element is not None:
if type == CONNECTOR:
name = "connector"
connection = plcopen.commonObjects_connector()
elif type == CONTINUATION:
name = "continuation"
connection = plcopen.commonObjects_continuation()
connection.setlocalId(id)
element.addinstance(name, connection)
def SetEditedElementConnectionInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
connection = element.getinstance(id)
if connection is None:
return
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.commonObjects_continuation):
connection.addconnectionPointOut()
connection.connectionPointOut.setrelPositionXY(position.x, position.y)
elif isinstance(connection, plcopen.commonObjects_connector):
connection.addconnectionPointIn()
connection.connectionPointIn.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(connection.connectionPointIn, value)
def AddEditedElementComment(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
comment = plcopen.commonObjects_comment()
comment.setlocalId(id)
element.addinstance("comment", comment)
def SetEditedElementCommentInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
comment = element.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 AddEditedElementPowerRail(self, tagname, id, type):
element = self.GetEditedElement(tagname)
if element is not None:
if type == LEFTRAIL:
name = "leftPowerRail"
powerrail = plcopen.ldObjects_leftPowerRail()
elif type == RIGHTRAIL:
name = "rightPowerRail"
powerrail = plcopen.ldObjects_rightPowerRail()
powerrail.setlocalId(id)
element.addinstance(name, powerrail)
def SetEditedElementPowerRailInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
powerrail = element.getinstance(id)
if powerrail is None:
return
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.ldObjects_leftPowerRail):
powerrail.setconnectionPointOut([])
for connector in value["outputs"]:
position = connector.GetRelPosition()
connection = plcopen.leftPowerRail_connectionPointOut()
connection.setrelPositionXY(position.x, position.y)
powerrail.connectionPointOut.append(connection)
elif isinstance(powerrail, plcopen.ldObjects_rightPowerRail):
powerrail.setconnectionPointIn([])
for connector in value["inputs"]:
position = connector.GetRelPosition()
connection = plcopen.connectionPointIn()
connection.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(connection, connector)
powerrail.connectionPointIn.append(connection)
def AddEditedElementContact(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
contact = plcopen.ldObjects_contact()
contact.setlocalId(id)
element.addinstance("contact", contact)
def SetEditedElementContactInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
contact = element.getinstance(id)
if contact is None:
return
for param, value in infos.items():
if param == "name":
contact.setvariable(value)
elif param == "type":
if value == CONTACT_NORMAL:
contact.setnegated(False)
contact.setedge("none")
elif value == CONTACT_REVERSE:
contact.setnegated(True)
contact.setedge("none")
elif value == CONTACT_RISING:
contact.setnegated(False)
contact.setedge("rising")
elif value == CONTACT_FALLING:
contact.setnegated(False)
contact.setedge("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["inputs"][0]
position = input_connector.GetRelPosition()
contact.addconnectionPointIn()
contact.connectionPointIn.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(contact.connectionPointIn, input_connector)
output_connector = value["outputs"][0]
position = output_connector.GetRelPosition()
contact.addconnectionPointOut()
contact.connectionPointOut.setrelPositionXY(position.x, position.y)
def AddEditedElementCoil(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
coil = plcopen.ldObjects_coil()
coil.setlocalId(id)
element.addinstance("coil", coil)
def SetEditedElementCoilInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
coil = element.getinstance(id)
if coil is None:
return
for param, value in infos.items():
if param == "name":
coil.setvariable(value)
elif param == "type":
if value == COIL_NORMAL:
coil.setnegated(False)
coil.setstorage("none")
coil.setedge("none")
elif value == COIL_REVERSE:
coil.setnegated(True)
coil.setstorage("none")
coil.setedge("none")
elif value == COIL_SET:
coil.setnegated(False)
coil.setstorage("set")
coil.setedge("none")
elif value == COIL_RESET:
coil.setnegated(False)
coil.setstorage("reset")
coil.setedge("none")
elif value == COIL_RISING:
coil.setnegated(False)
coil.setstorage("none")
coil.setedge("rising")
elif value == COIL_FALLING:
coil.setnegated(False)
coil.setstorage("none")
coil.setedge("falling")
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["inputs"][0]
position = input_connector.GetRelPosition()
coil.addconnectionPointIn()
coil.connectionPointIn.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(coil.connectionPointIn, input_connector)
output_connector = value["outputs"][0]
position = output_connector.GetRelPosition()
coil.addconnectionPointOut()
coil.connectionPointOut.setrelPositionXY(position.x, position.y)
def AddEditedElementStep(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
step = plcopen.sfcObjects_step()
step.setlocalId(id)
element.addinstance("step", step)
def SetEditedElementStepInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
step = element.getinstance(id)
if step is None:
return
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":
if len(value["inputs"]) > 0:
input_connector = value["inputs"][0]
position = input_connector.GetRelPosition()
step.addconnectionPointIn()
step.connectionPointIn.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(step.connectionPointIn, input_connector)
else:
step.deleteconnectionPointIn()
if len(value["outputs"]) > 0:
output_connector = value["outputs"][0]
position = output_connector.GetRelPosition()
step.addconnectionPointOut()
step.connectionPointOut.setrelPositionXY(position.x, position.y)
else:
step.deleteconnectionPointOut()
elif param == "action":
if value:
position = value.GetRelPosition()
step.addconnectionPointOutAction()
step.connectionPointOutAction.setrelPositionXY(position.x, position.y)
else:
step.deleteconnectionPointOutAction()
def AddEditedElementTransition(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
transition = plcopen.sfcObjects_transition()
transition.setlocalId(id)
element.addinstance("transition", transition)
def SetEditedElementTransitionInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
transition = element.getinstance(id)
if transition is None:
return
for param, value in infos.items():
if param == "type" and value != "connection":
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 == "priority":
if value != 0:
transition.setpriority(value)
else:
transition.setpriority(None)
elif param == "connectors":
input_connector = value["inputs"][0]
position = input_connector.GetRelPosition()
transition.addconnectionPointIn()
transition.connectionPointIn.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(transition.connectionPointIn, input_connector)
output_connector = value["outputs"][0]
position = output_connector.GetRelPosition()
transition.addconnectionPointOut()
transition.connectionPointOut.setrelPositionXY(position.x, position.y)
elif infos.get("type", None) == "connection" and param == "connection" and value:
transition.setconditionContent("connection", None)
self.SetConnectionWires(transition.condition.content["value"], value)
def AddEditedElementDivergence(self, tagname, id, type):
element = self.GetEditedElement(tagname)
if element is not None:
if type == SELECTION_DIVERGENCE:
name = "selectionDivergence"
divergence = plcopen.sfcObjects_selectionDivergence()
elif type == SELECTION_CONVERGENCE:
name = "selectionConvergence"
divergence = plcopen.sfcObjects_selectionConvergence()
elif type == SIMULTANEOUS_DIVERGENCE:
name = "simultaneousDivergence"
divergence = plcopen.sfcObjects_simultaneousDivergence()
elif type == SIMULTANEOUS_CONVERGENCE:
name = "simultaneousConvergence"
divergence = plcopen.sfcObjects_simultaneousConvergence()
divergence.setlocalId(id)
element.addinstance(name, divergence)
def SetEditedElementDivergenceInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
divergence = element.getinstance(id)
if divergence is None:
return
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.sfcObjects_selectionDivergence, plcopen.sfcObjects_simultaneousDivergence)):
position = input_connectors[0].GetRelPosition()
divergence.addconnectionPointIn()
divergence.connectionPointIn.setrelPositionXY(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.sfcObjects_selectionConvergence):
connection = plcopen.selectionConvergence_connectionPointIn()
else:
connection = plcopen.connectionPointIn()
connection.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(connection, input_connector)
divergence.appendconnectionPointIn(connection)
output_connectors = value["outputs"]
if isinstance(divergence, (plcopen.sfcObjects_selectionConvergence, plcopen.sfcObjects_simultaneousConvergence)):
position = output_connectors[0].GetRelPosition()
divergence.addconnectionPointOut()
divergence.connectionPointOut.setrelPositionXY(position.x, position.y)
else:
divergence.setconnectionPointOut([])
for output_connector in output_connectors:
position = output_connector.GetRelPosition()
if isinstance(divergence, plcopen.sfcObjects_selectionDivergence):
connection = plcopen.selectionDivergence_connectionPointOut()
else:
connection = plcopen.simultaneousDivergence_connectionPointOut()
connection.setrelPositionXY(position.x, position.y)
divergence.appendconnectionPointOut(connection)
def AddEditedElementJump(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
jump = plcopen.sfcObjects_jumpStep()
jump.setlocalId(id)
element.addinstance("jumpStep", jump)
def SetEditedElementJumpInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
jump = element.getinstance(id)
if jump is None:
return
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.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(jump.connectionPointIn, value)
def AddEditedElementActionBlock(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
actionBlock = plcopen.commonObjects_actionBlock()
actionBlock.setlocalId(id)
element.addinstance("actionBlock", actionBlock)
def SetEditedElementActionBlockInfos(self, tagname, id, infos):
element = self.GetEditedElement(tagname)
if element is not None:
actionBlock = element.getinstance(id)
if actionBlock is None:
return
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.setrelPositionXY(position.x, position.y)
self.SetConnectionWires(actionBlock.connectionPointIn, value)
def RemoveEditedElementInstance(self, tagname, id):
element = self.GetEditedElement(tagname)
if element is not None:
instance = element.getinstance(id)
if isinstance(instance, plcopen.fbdObjects_block):
self.RemoveEditedElementPouVar(tagname, instance.gettypeName(), instance.getinstanceName())
element.removeinstance(id)
self.Project.RefreshElementUsingTree()
def GetEditedResourceVariables(self, tagname, debug = False):
varlist = []
words = tagname.split("::")
for var in self.GetConfigurationGlobalVars(words[1], debug):
if var["Type"] == "BOOL":
varlist.append(var["Name"])
for var in self.GetConfigurationResourceGlobalVars(words[1], words[2], debug):
if var["Type"] == "BOOL":
varlist.append(var["Name"])
return varlist
def SetEditedResourceInfos(self, tagname, tasks, instances):
resource = self.GetEditedElement(tagname)
if resource is not None:
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"])
## result = duration_model.match(task["Interval"]).groups()
## if reduce(lambda x, y: x or y != None, result):
## values = []
## for value in result[:-1]:
## if value != None:
## values.append(int(value))
## else:
## values.append(0)
## if result[-1] is not None:
## values.append(int(float(result[-1]) * 1000))
## new_task.setinterval(datetime.time(*values))
if task["Interval"] != "":
new_task.setinterval(task["Interval"])
new_task.setpriority(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.settypeName(instance["Type"])
task_list.get(instance["Task"], resource).appendpouInstance(new_instance)
def GetEditedResourceInfos(self, tagname, debug = False):
resource = self.GetEditedElement(tagname, debug)
if resource is not None:
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:
## text = ""
## if interval.hour != 0:
## text += "%dh"%interval.hour
## if interval.minute != 0:
## text += "%dm"%interval.minute
## if interval.second != 0:
## text += "%ds"%interval.second
## if interval.microsecond != 0:
## if interval.microsecond % 1000 != 0:
## text += "%.3fms"%(float(interval.microsecond) / 1000)
## else:
## text += "%dms"%(interval.microsecond / 1000)
## new_task["Interval"] = text
new_task["Interval"] = interval
else:
new_task["Interval"] = ""
new_task["Priority"] = str(task.getpriority())
tasks_data.append(new_task)
for instance in task.getpouInstance():
new_instance = {}
new_instance["Name"] = instance.getname()
new_instance["Type"] = instance.gettypeName()
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.gettypeName()
new_instance["Task"] = ""
instances_data.append(new_instance)
return tasks_data, instances_data
def OpenXMLFile(self, filepath):
xmlfile = open(filepath, 'r')
tree = minidom.parse(xmlfile)
xmlfile.close()
self.Project = plcopen.project()
for child in tree.childNodes:
if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "project":
try:
result = self.Project.loadXMLTree(child, ["xmlns", "xmlns:xhtml", "xmlns:xsi", "xsi:schemaLocation"])
except ValueError, e:
return _("Project file syntax error:\n\n") + str(e)
self.SetFilePath(filepath)
self.Project.RefreshElementUsingTree()
self.Project.RefreshDataTypeHierarchy()
self.Project.RefreshCustomBlockTypes()
self.CreateProjectBuffer(True)
self.ProgramChunks = []
self.ProgramOffset = 0
self.NextCompiledProject = self.Copy(self.Project)
self.CurrentCompiledProject = None
self.Buffering = False
self.CurrentElementEditing = None
return None
return _("No PLC project found")
def SaveXMLFile(self, filepath = None):
if not filepath and self.FilePath == "":
return False
else:
contentheader = self.Project.getcontentHeader()
contentheader["modificationDateTime"] = datetime.datetime(*localtime()[:6])
self.Project.setcontentHeader(contentheader)
text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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"}
text += self.Project.generateXMLText("project", 0, extras)
if filepath:
xmlfile = open(filepath,"w")
else:
xmlfile = open(self.FilePath,"w")
xmlfile.write(text.encode("utf-8"))
xmlfile.close()
self.MarkProjectAsSaved()
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 CreateProjectBuffer(self, saved):
if self.ProjectBufferEnabled:
self.ProjectBuffer = UndoBuffer(cPickle.dumps(self.Project), saved)
else:
self.ProjectBuffer = None
self.ProjectSaved = saved
def IsProjectBufferEnabled(self):
return self.ProjectBufferEnabled
def EnableProjectBuffer(self, enable):
self.ProjectBufferEnabled = enable
if self.Project is not None:
if enable:
current_saved = self.ProjectSaved
else:
current_saved = self.ProjectBuffer.IsCurrentSaved()
self.CreateProjectBuffer(current_saved)
def BufferProject(self):
if self.ProjectBuffer is not None:
self.ProjectBuffer.Buffering(cPickle.dumps(self.Project))
else:
self.ProjectSaved = False
def StartBuffering(self):
if self.ProjectBuffer is not None:
self.Buffering = True
else:
self.ProjectSaved = False
def EndBuffering(self):
if self.ProjectBuffer is not None and self.Buffering:
self.ProjectBuffer.Buffering(cPickle.dumps(self.Project))
self.Buffering = False
def MarkProjectAsSaved(self):
if self.ProjectBuffer is not None:
self.ProjectBuffer.CurrentSaved()
else:
self.ProjectSaved = True
# Return if project is saved
def ProjectIsSaved(self):
if self.ProjectBuffer is not None:
return self.ProjectBuffer.IsCurrentSaved() and not self.Buffering
else:
return self.ProjectSaved
def LoadPrevious(self):
if self.ProjectBuffer is not None:
if self.Buffering:
self.EndBuffering()
self.Project = cPickle.loads(self.ProjectBuffer.Previous())
def LoadNext(self):
if self.ProjectBuffer is not None:
self.Project = cPickle.loads(self.ProjectBuffer.Next())
def GetBufferState(self):
if self.ProjectBuffer is not None:
first = self.ProjectBuffer.IsFirst()
last = self.ProjectBuffer.IsLast() and not self.Buffering
return not first, not last
return False, False