# HG changeset patch # User Edouard Tisserant # Date 1402588230 -7200 # Node ID c97dc528141989a5c1aec8f84ebfb4564908323a # Parent 3742380396430c3621bb7bd0977fab86617724cb Fixed declaration and ST code gen for IEC function that return derivated types diff -r 374238039643 -r c97dc5281419 PLCControler.py --- a/PLCControler.py Wed Jun 11 19:01:17 2014 +0200 +++ b/PLCControler.py Thu Jun 12 17:50:30 2014 +0200 @@ -1467,7 +1467,7 @@ else: derived_type = PLCOpenParser.CreateElement("derived", "dataType") derived_type.setname(return_type) - return_type.setcontent(derived_type) + return_type_obj.setcontent(derived_type) def UpdateProjectUsedPous(self, old_name, new_name): if self.Project is not None: diff -r 374238039643 -r c97dc5281419 PLCGenerator.py --- a/PLCGenerator.py Wed Jun 11 19:01:17 2014 +0200 +++ b/PLCGenerator.py Thu Jun 12 17:50:30 2014 +0200 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. +#based on the plcopen standard. # #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD # @@ -27,14 +27,14 @@ from types import * import re -# Dictionary associating PLCOpen variable categories to the corresponding +# Dictionary associating PLCOpen variable categories to the corresponding # IEC 61131-3 variable categories -varTypeNames = {"localVars" : "VAR", "tempVars" : "VAR_TEMP", "inputVars" : "VAR_INPUT", +varTypeNames = {"localVars" : "VAR", "tempVars" : "VAR_TEMP", "inputVars" : "VAR_INPUT", "outputVars" : "VAR_OUTPUT", "inOutVars" : "VAR_IN_OUT", "externalVars" : "VAR_EXTERNAL", "globalVars" : "VAR_GLOBAL", "accessVars" : "VAR_ACCESS"} -# Dictionary associating PLCOpen POU categories to the corresponding +# Dictionary associating PLCOpen POU categories to the corresponding # IEC 61131-3 POU categories pouTypeNames = {"function" : "FUNCTION", "functionBlock" : "FUNCTION_BLOCK", "program" : "PROGRAM"} @@ -125,16 +125,16 @@ if not self.DatatypeComputed.get(datatype_name, True): # If not mark data type as computed self.DatatypeComputed[datatype_name] = True - + # Getting datatype model from project datatype = self.Project.getdataType(datatype_name) tagname = self.Controler.ComputeDataTypeName(datatype.getname()) - datatype_def = [(" ", ()), + datatype_def = [(" ", ()), (datatype.getname(), (tagname, "name")), (" : ", ())] basetype_content = datatype.baseType.getcontent() basetype_content_type = basetype_content.getLocalTag() - # Data type derived directly from a user defined type + # Data type derived directly from a user defined type if basetype_content_type == "derived": basetype_name = basetype_content.getname() self.GenerateDataType(basetype_name) @@ -143,11 +143,11 @@ elif basetype_content_type in ["subrangeSigned", "subrangeUnsigned"]: base_type = basetype_content.baseType.getcontent() base_type_type = base_type.getLocalTag() - # Subrange derived directly from a user defined type + # Subrange derived directly from a user defined type if base_type_type == "derived": basetype_name = base_type_type.getname() self.GenerateDataType(basetype_name) - # Subrange derived directly from an elementary type + # Subrange derived directly from an elementary type else: basetype_name = base_type_type min_value = basetype_content.range.getlower() @@ -162,7 +162,7 @@ elif basetype_content_type == "enum": values = [[(value.getname(), (tagname, "value", i))] for i, value in enumerate( - basetype_content.xpath("ppx:values/ppx:value", + basetype_content.xpath("ppx:values/ppx:value", namespaces=PLCOpenParser.NSMAP))] datatype_def += [("(", ())] datatype_def += JoinList([(", ", ())], values) @@ -171,16 +171,16 @@ elif basetype_content_type == "array": base_type = basetype_content.baseType.getcontent() base_type_type = base_type.getLocalTag() - # Array derived directly from a user defined type + # Array derived directly from a user defined type if base_type_type == "derived": basetype_name = base_type.getname() self.GenerateDataType(basetype_name) - # Array derived directly from an elementary type + # Array derived directly from an elementary type else: basetype_name = base_type_type.upper() dimensions = [[("%s"%dimension.getlower(), (tagname, "range", i, "lower")), ("..", ()), - ("%s"%dimension.getupper(), (tagname, "range", i, "upper"))] + ("%s"%dimension.getupper(), (tagname, "range", i, "upper"))] for i, dimension in enumerate(basetype_content.getdimension())] datatype_def += [("ARRAY [", ())] datatype_def += JoinList([(",", ())], dimensions) @@ -192,24 +192,24 @@ for i, element in enumerate(basetype_content.getvariable()): element_type = element.type.getcontent() element_type_type = element_type.getLocalTag() - # Structure element derived directly from a user defined type + # Structure element derived directly from a user defined type if element_type_type == "derived": elementtype_name = element_type.getname() self.GenerateDataType(elementtype_name) elif element_type_type == "array": base_type = element_type.baseType.getcontent() base_type_type = base_type.getLocalTag() - # Array derived directly from a user defined type + # Array derived directly from a user defined type if base_type_type == "derived": basetype_name = base_type.getname() self.GenerateDataType(basetype_name) - # Array derived directly from an elementary type + # Array derived directly from an elementary type else: basetype_name = base_type_type.upper() dimensions = ["%s..%s" % (dimension.getlower(), dimension.getupper()) for dimension in element_type.getdimension()] elementtype_name = "ARRAY [%s] OF %s" % (",".join(dimensions), basetype_name) - # Structure element derived directly from an elementary type + # Structure element derived directly from an elementary type else: elementtype_name = element_type_type.upper() element_text = [("\n ", ()), @@ -224,7 +224,7 @@ datatype_def += [("STRUCT", ())] datatype_def += JoinList([("", ())], elements) datatype_def += [("\n END_STRUCT", ())] - # Data type derived directly from a elementary type + # Data type derived directly from a elementary type else: datatype_def += [(basetype_content_type.upper(), (tagname, "base"))] # Data type has an initial value @@ -240,7 +240,7 @@ if not self.PouComputed.get(pou_name, True): # If not mark POU as computed self.PouComputed[pou_name] = True - + # Getting POU model from project pou = self.Project.getpou(pou_name) pou_type = pou.getpouType() @@ -252,14 +252,14 @@ self.Program += program else: raise PLCGenException, _("Undefined pou type \"%s\"")%pou_type - + # Generate a POU defined and used in text def GeneratePouProgramInText(self, text): for pou_name in self.PouComputed.keys(): model = re.compile("(?:^|[^0-9^A-Z])%s(?:$|[^0-9^A-Z])"%pou_name.upper()) if model.search(text) is not None: self.GeneratePouProgram(pou_name) - + # Generate a configuration from its model def GenerateConfiguration(self, configuration): tagname = self.Controler.ComputeConfigurationName(configuration.getname()) @@ -267,20 +267,20 @@ (configuration.getname(), (tagname, "name")), ("\n", ())] var_number = 0 - + varlists = [(varlist, varlist.getvariable()[:]) for varlist in configuration.getglobalVars()] - + extra_variables = self.Controler.GetConfigurationExtraVariables() extra_global_vars = None if len(extra_variables) > 0 and len(varlists) == 0: extra_global_vars = PLCOpenParser.CreateElement("globalVars", "interface") configuration.setglobalVars([extra_global_vars]) varlists = [(extra_global_vars, [])] - + for variable in extra_variables: varlists[-1][0].appendvariable(variable) varlists[-1][1].append(variable) - + # Generate any global variable in configuration for varlist, varlist_variables in varlists: variable_type = errorVarTypes.get("VAR_GLOBAL", "var_local") @@ -301,7 +301,7 @@ self.GenerateDataType(var_type) else: var_type = var.gettypeAsText() - + config += [(" ", ()), (var.getname(), (tagname, variable_type, var_number, "name")), (" ", ())] @@ -321,19 +321,19 @@ config += [(";\n", ())] var_number += 1 config += [(" END_VAR\n", ())] - + if extra_global_vars is not None: configuration.remove(extra_global_vars) else: for variable in extra_variables: varlists[-1][0].remove(variable) - + # Generate any resource in the configuration for resource in configuration.getresource(): config += self.GenerateResource(resource, configuration.getname()) config += [("END_CONFIGURATION\n", ())] return config - + # Generate a resource from its model def GenerateResource(self, resource, config_name): tagname = self.Controler.ComputeConfigurationResourceName(config_name, resource.getname()) @@ -361,7 +361,7 @@ self.GenerateDataType(var_type) else: var_type = var.gettypeAsText() - + resrce += [(" ", ()), (var.getname(), (tagname, variable_type, var_number, "name")), (" ", ())] @@ -413,7 +413,7 @@ ## resrce += [("%dms"%(interval.microsecond / 1000), (tagname, "task", task_number, "interval", "millisecond"))] ## resrce += [(",", ())] # Priority argument - resrce += [("PRIORITY := ", ()), + resrce += [("PRIORITY := ", ()), ("%d"%task.getpriority(), (tagname, "task", task_number, "priority")), (");\n", ())] task_number += 1 @@ -439,16 +439,16 @@ instance_number += 1 resrce += [(" END_RESOURCE\n", ())] return resrce - + # Generate the entire program for current project - def GenerateProgram(self): + def GenerateProgram(self): # Find all data types defined for datatype in self.Project.getdataTypes(): self.DatatypeComputed[datatype.getname()] = False # Find all data types defined for pou in self.Project.getpous(): self.PouComputed[pou.getname()] = False - # Generate data type declaration structure if there is at least one data + # Generate data type declaration structure if there is at least one data # type defined if len(self.DatatypeComputed) > 0: self.Program += [("TYPE\n", ())] @@ -462,7 +462,7 @@ # Generate every configurations defined for config in self.Project.getconfigurations(): self.Program += self.GenerateConfiguration(config) - + # Return generated program def GetGeneratedProgram(self): return self.Program @@ -481,18 +481,18 @@ [ContactClass, CoilClass, LeftPowerRailClass, RightPowerRailClass] = [ PLCOpenParser.GetElementClass(instance_name, "ldObjects") for instance_name in ["contact", "coil", "leftPowerRail", "rightPowerRail"]] -[StepClass, TransitionClass, JumpStepClass, +[StepClass, TransitionClass, JumpStepClass, SelectionConvergenceClass, SelectionDivergenceClass, SimultaneousConvergenceClass, SimultaneousDivergenceClass] = [ PLCOpenParser.GetElementClass(instance_name, "sfcObjects") - for instance_name in ["step", "transition", "jumpStep", + for instance_name in ["step", "transition", "jumpStep", "selectionConvergence", "selectionDivergence", "simultaneousConvergence", "simultaneousDivergence"]] TransitionObjClass = PLCOpenParser.GetElementClass("transition", "transitions") ActionObjClass = PLCOpenParser.GetElementClass("action", "actions") class PouProgramGenerator: - + # Create a new POU program generator def __init__(self, parent, name, type, errors, warnings): # Keep Reference to the parent generator @@ -514,22 +514,22 @@ self.Program = [] self.Errors = errors self.Warnings = warnings - + def GetBlockType(self, type, inputs=None): return self.ParentGenerator.Controler.GetBlockType(type, inputs) - + def IndentLeft(self): if len(self.CurrentIndent) >= 2: self.CurrentIndent = self.CurrentIndent[:-2] - + def IndentRight(self): self.CurrentIndent += " " - + # Generator of unique ID for inline actions def GetActionNumber(self): self.ActionNumber += 1 return self.ActionNumber - + # Test if a variable has already been defined def IsAlreadyDefined(self, name): for list_type, option, located, vars in self.Interface: @@ -537,7 +537,7 @@ if name == var_name: return True return False - + # Return the type of a variable defined in interface def GetVariableType(self, name): parts = name.split('.') @@ -569,18 +569,18 @@ current_type = element["Type"] break return current_type - + # Return connectors linked by a connection to the given connector def GetConnectedConnector(self, connector, body): links = connector.getconnections() if links is not None and len(links) == 1: return self.GetLinkedConnector(links[0], body) - return None + return None def GetLinkedConnector(self, link, body): parameter = link.getformalParameter() instance = body.getcontentInstance(link.getrefLocalId()) - if isinstance(instance, (InVariableClass, InOutVariableClass, + if isinstance(instance, (InVariableClass, InOutVariableClass, ContinuationClass, ContactClass, CoilClass)): return instance.connectionPointOut elif isinstance(instance, BlockClass): @@ -610,13 +610,13 @@ if point.x == powerrailposition.x + relposition[0] and point.y == powerrailposition.y + relposition[1]: return outputconnection return None - + def ExtractRelatedConnections(self, connection): for i, related in enumerate(self.RelatedConnections): if connection in related: return self.RelatedConnections.pop(i) return [connection] - + def ComputeInterface(self, pou): interface = pou.getinterface() if interface is not None: @@ -626,7 +626,7 @@ body_content = body.getcontent() body_type = body_content.getLocalTag() if self.Type == "FUNCTION": - returntype_content = interface.getreturnType().getcontent() + returntype_content = interface.getreturnType()[0] returntype_content_type = returntype_content.getLocalTag() if returntype_content_type == "derived": self.ReturnType = returntype_content.getname() @@ -680,7 +680,7 @@ self.Interface.append((varTypeNames[varlist_type], option, False, variables)) if len(located) > 0: self.Interface.append((varTypeNames[varlist_type], option, True, located)) - + LITERAL_TYPES = { "T": "TIME", "D": "DATE", @@ -699,11 +699,11 @@ if body_type in ["FBD", "LD", "SFC"]: undefined_blocks = [] for instance in body.getcontentInstances(): - if isinstance(instance, (InVariableClass, OutVariableClass, + if isinstance(instance, (InVariableClass, OutVariableClass, InOutVariableClass)): expression = instance.getexpression() var_type = self.GetVariableType(expression) - if (isinstance(pou, TransitionObjClass) + if (isinstance(pou, TransitionObjClass) and expression == pou.getname()): var_type = "BOOL" elif (not isinstance(pou, (TransitionObjClass, ActionObjClass)) and @@ -718,7 +718,7 @@ parts = expression.split("#") if len(parts) > 1: literal_prefix = parts[0].upper() - var_type = self.LITERAL_TYPES.get(literal_prefix, + var_type = self.LITERAL_TYPES.get(literal_prefix, literal_prefix) elif expression.startswith("'"): var_type = "STRING" @@ -822,7 +822,7 @@ self.TagName = self.ParentGenerator.Controler.ComputePouTransitionName(self.Name, transition.getname()) self.ComputeConnectionTypes(transition) self.TagName = previous_tagname - + def ComputeBlockInputTypes(self, instance, block_infos, body): undefined = {} for variable in instance.outputVariables.getvariable(): @@ -883,7 +883,7 @@ if body_type in ["IL","ST"]: text = body_content.getanyText() self.ParentGenerator.GeneratePouProgramInText(text.upper()) - self.Program = [(ReIndentText(text, len(self.CurrentIndent)), + self.Program = [(ReIndentText(text, len(self.CurrentIndent)), (self.TagName, "body", len(self.CurrentIndent)))] elif body_type == "SFC": self.IndentRight() @@ -966,7 +966,7 @@ self.Program += [(self.CurrentIndent, ())] self.Program += [(instance.getvariable(), coil_info + ("reference",))] self.Program += [(" := ", ())] + expression + [(";\n", ())] - + def FactorizePaths(self, paths): same_paths = {} uncomputed_index = range(len(paths)) @@ -984,7 +984,7 @@ if len(elements) > 1: elements_paths = self.FactorizePaths([path for path, num in elements]) if len(elements_paths) > 1: - factorized_paths.append([tuple(elements_paths)] + eval(same_path)) + factorized_paths.append([tuple(elements_paths)] + eval(same_path)) else: factorized_paths.append(elements_paths + eval(same_path)) for path, num in elements: @@ -1013,7 +1013,7 @@ self.ComputedBlocks[block] = True connected_vars = [] if not block_infos["extensible"]: - input_connected = dict([("EN", None)] + + input_connected = dict([("EN", None)] + [(input_name, None) for input_name in input_names]) for variable in input_variables: parameter = variable.getformalParameter() @@ -1071,7 +1071,7 @@ else: self.Interface[-1][3].append(("ANY", variable_name, None, None)) if len(output_variables) > 1 and parameter not in ["", "OUT"]: - vars.append([(parameter, (self.TagName, "block", block.getlocalId(), "output", i)), + vars.append([(parameter, (self.TagName, "block", block.getlocalId(), "output", i)), (" => %s"%variable_name, ())]) else: output_info = (self.TagName, "block", block.getlocalId(), "output", i) @@ -1105,19 +1105,19 @@ if expression is not None: vars.append([(parameter, input_info), (" := ", ())] + self.ExtractModifier(variable, expression, input_info)) - self.Program += [(self.CurrentIndent, ()), + self.Program += [(self.CurrentIndent, ()), (name, (self.TagName, "block", block.getlocalId(), "name")), ("(", ())] self.Program += JoinList([(", ", ())], vars) self.Program += [(");\n", ())] - + if link is not None: connectionPoint = link.getposition()[-1] output_parameter = link.getformalParameter() else: connectionPoint = None output_parameter = None - + output_variable = None output_idx = 0 if output_parameter is not None: @@ -1130,13 +1130,13 @@ else: for i, variable in enumerate(output_variables): blockPointx, blockPointy = variable.connectionPointOut.getrelPositionXY() - if (connectionPoint is None or - block.getx() + blockPointx == connectionPoint.getx() and + if (connectionPoint is None or + block.getx() + blockPointx == connectionPoint.getx() and block.gety() + blockPointy == connectionPoint.gety()): output_variable = variable output_parameter = variable.getformalParameter() output_idx = i - + if output_variable is not None: if block_infos["type"] == "function": output_info = (self.TagName, "block", block.getlocalId(), "output", output_idx) @@ -1149,7 +1149,7 @@ output_name = "%s%d_%s"%(type, block.getlocalId(), output_parameter) output_value = [(output_name, output_info)] return self.ExtractModifier(output_variable, output_value, output_info) - + if block_infos["type"] == "functionBlock": output_info = (self.TagName, "block", block.getlocalId(), "output", output_idx) output_name = self.ExtractModifier(output_variable, [("%s.%s"%(name, output_parameter), output_info)], output_info) @@ -1168,7 +1168,7 @@ self.Program += output_name self.Program += [(";\n", ())] return [(variable_name, ())] - return output_name + return output_name if link is not None: if output_parameter is None: output_parameter = "" @@ -1291,7 +1291,7 @@ elif edge == "falling": return self.AddTrigger("F_TRIG", expression, var_info + ("falling",)) return expression - + def AddTrigger(self, edge, expression, var_info): if self.Interface[-1][0] != "VAR" or self.Interface[-1][1] is not None or self.Interface[-1][2]: self.Interface.append(("VAR", None, False, [])) @@ -1301,11 +1301,11 @@ i += 1 name = "%s%d"%(edge, i) self.Interface[-1][3].append((edge, name, None, None)) - self.Program += [(self.CurrentIndent, ()), (name, var_info), ("(CLK := ", ())] + self.Program += [(self.CurrentIndent, ()), (name, var_info), ("(CLK := ", ())] self.Program += expression self.Program += [(");\n", ())] return [("%s.Q"%name, var_info)] - + def ExtractDivergenceInput(self, divergence, pou): connectionPointIn = divergence.getconnectionPointIn() if connectionPointIn is not None: @@ -1335,9 +1335,9 @@ if step_name not in self.SFCNetworks["Steps"].keys(): if step.getinitialStep(): self.InitialSteps.append(step_name) - step_infos = {"id" : step.getlocalId(), - "initial" : step.getinitialStep(), - "transitions" : [], + step_infos = {"id" : step.getlocalId(), + "initial" : step.getinitialStep(), + "transitions" : [], "actions" : []} self.SFCNetworks["Steps"][step_name] = step_infos if step.connectionPointIn is not None: @@ -1365,7 +1365,7 @@ if instance in self.SFCNetworks["Transitions"].keys(): target_info = (self.TagName, "transition", instance.getlocalId(), "to", step_infos["id"]) self.SFCNetworks["Transitions"][instance]["to"].append([(step_name, target_info)]) - + def GenerateSFCJump(self, jump, pou): jump_target = jump.gettargetName() if jump.connectionPointIn is not None: @@ -1393,7 +1393,7 @@ if instance in self.SFCNetworks["Transitions"].keys(): target_info = (self.TagName, "jump", jump.getlocalId(), "target") self.SFCNetworks["Transitions"][instance]["to"].append([(jump_target, target_info)]) - + def GenerateSFCStepActions(self, actionBlock, pou): connections = actionBlock.connectionPointIn.getconnections() if connections is not None and len(connections) == 1: @@ -1407,8 +1407,8 @@ if step_name in self.SFCNetworks["Steps"].keys(): actions = actionBlock.getactions() for i, action in enumerate(actions): - action_infos = {"id" : actionBlock.getlocalId(), - "qualifier" : action["qualifier"], + action_infos = {"id" : actionBlock.getlocalId(), + "qualifier" : action["qualifier"], "content" : action["value"], "num" : i} if "duration" in action: @@ -1419,12 +1419,12 @@ self.GenerateSFCAction(action["value"], pou) else: action_name = "%s_INLINE%d"%(step_name.upper(), self.GetActionNumber()) - self.SFCNetworks["Actions"][action_name] = ([(self.CurrentIndent, ()), + self.SFCNetworks["Actions"][action_name] = ([(self.CurrentIndent, ()), (action["value"], (self.TagName, "action_block", action_infos["id"], "action", i, "inline")), ("\n", ())], ()) action_infos["content"] = action_name self.SFCNetworks["Steps"][step_name]["actions"].append(action_infos) - + def GenerateSFCAction(self, action_name, pou): if action_name not in self.SFCNetworks["Actions"].keys(): actionContent = pou.getaction(action_name) @@ -1435,7 +1435,7 @@ self.SFCNetworks["Actions"][action_name] = (self.Program, (self.TagName, "name")) self.Program = [] self.TagName = previous_tagname - + def GenerateSFCTransition(self, transition, pou): if transition not in self.SFCNetworks["Transitions"].keys(): steps = [] @@ -1457,9 +1457,9 @@ steps.extend(self.ExtractConvergenceInputs(step, pou)) elif isinstance(instance, SimultaneousConvergenceClass): steps.extend(self.ExtractConvergenceInputs(instance, pou)) - transition_infos = {"id" : transition.getlocalId(), - "priority": transition.getpriority(), - "from": [], + transition_infos = {"id" : transition.getlocalId(), + "priority": transition.getpriority(), + "from": [], "to" : [], "content": []} self.SFCNetworks["Transitions"][transition] = transition_infos @@ -1546,7 +1546,7 @@ self.ComputeSFCAction(action) for transition in step_infos["transitions"]: self.ComputeSFCTransition(transition) - + def ComputeSFCAction(self, action_name): if action_name in self.SFCNetworks["Actions"].keys(): action_content, action_info = self.SFCNetworks["Actions"].pop(action_name) @@ -1555,7 +1555,7 @@ (":\n", ())] self.Program += action_content self.Program += [("%sEND_ACTION\n\n"%self.CurrentIndent, ())] - + def ComputeSFCTransition(self, transition): if transition in self.SFCNetworks["Transitions"].keys(): transition_infos = self.SFCNetworks["Transitions"].pop(transition) @@ -1586,12 +1586,12 @@ self.Program += [("%sEND_TRANSITION\n\n"%self.CurrentIndent, ())] for [(step_name, step_infos)] in transition_infos["to"]: self.ComputeSFCStep(step_name) - + def GenerateProgram(self, pou): self.ComputeInterface(pou) self.ComputeConnectionTypes(pou) self.ComputeProgram(pou) - + program = [("%s "%self.Type, ()), (self.Name, (self.TagName, "name"))] if self.ReturnType is not None: