diff -r 635d0817508c -r 394d9f168258 PLCGenerator.py --- a/PLCGenerator.py Tue Nov 27 12:58:34 2007 +0100 +++ b/PLCGenerator.py Thu Dec 06 18:05:29 2007 +0100 @@ -34,6 +34,7 @@ currentProject = None currentProgram = "" +datatypeComputed = {} pouComputed = {} def ReIndentText(text, nb_spaces): @@ -53,6 +54,49 @@ compute += "\n" return compute +def GenerateDataType(datatype_name): + if not datatypeComputed.get(datatype_name, True): + datatypeComputed[datatype_name] = True + global currentProject, currentProgram + datatype = currentProject.getDataType(datatype_name) + datatype_def = " %s :"%datatype.getName() + basetype_content = datatype.baseType.getContent() + if basetype_content["value"] is None: + datatype_def += " %s"%basetype_content["name"] + elif basetype_content["name"] == "derived": + basetype_name = basetype_content["value"].getName() + GenerateDataType(basetype_name) + datatype_def += " %s"%basetype_name + elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]: + base_type = basetype_content["value"].baseType.getContent() + if base_type["value"] is None: + basetype_name = base_type["name"] + else: + basetype_name = base_type["value"].getName() + GenerateDataType(basetype_name) + min_value = basetype_content["value"].range.getLower() + max_value = basetype_content["value"].range.getUpper() + datatype_def += " %s (%d..%d)"%(basetype_name, min_value, max_value) + elif basetype_content["name"] == "enum": + values = [] + for value in basetype_content["value"].values.getValue(): + values.append(value.getName()) + datatype_def += " (%s)"%", ".join(values) + elif basetype_content["name"] == "array": + base_type = basetype_content["value"].baseType.getContent() + if base_type["value"] is None: + basetype_name = base_type["name"] + else: + basetype_name = base_type["value"].getName() + GenerateDataType(basetype_name) + dimensions = [] + for dimension in basetype_content["value"].getDimension(): + dimensions.append("0..%d"%(dimension.getUpper() - 1)) + datatype_def += " ARRAY [%s] OF %s"%(",".join(dimensions), basetype_name) + if datatype.initialValue is not None: + datatype_def += " := %s"%str(datatype.initialValue.getValue()) + currentProgram += "%s;\n"%datatype_def + def GeneratePouProgram(pou_name): if not pouComputed.get(pou_name, True): pouComputed[pou_name] = True @@ -64,6 +108,8 @@ else: raise ValueError, "Undefined pou type" pou_program.GenerateInterface(pou.getInterface()) + pou_program.GenerateConnectionTypes(pou) + #print pou.getName(), pou_program.ConnectionTypes, pou_program.RelatedConnections pou_program.GenerateProgram(pou) currentProgram += pou_program.GenerateSTProgram() @@ -77,7 +123,11 @@ config += " CONSTANT" config += "\n" for var in varlist.getVariable(): - var_type = var.getType().getValue() + vartype_content = var.getType().getContent() + if vartype_content["value"] is None: + var_type = vartype_content["name"] + else: + var_type = vartype_content["value"].getName() config += " %s "%var.getName() address = var.getAddress() if address: @@ -110,12 +160,16 @@ resrce += " CONSTANT" resrce += "\n" for var in varlist.getVariable(): - var_type = var.getType().getValue() + vartype_content = var.getType().getContent() + if vartype_content["value"] is None: + var_type = vartype_content["name"] + else: + var_type = vartype_content["value"].getName() resrce += " %s "%var.getName() address = var.getAddress() if address: resrce += "AT %s "%address - resrce += ": %s"%var.getType().getValue() + resrce += ": %s"%var_type initial = var.getInitialValue() if initial: value = str(initial.getValue()) @@ -171,6 +225,8 @@ self.InitialSteps = [] self.ComputedBlocks = {} self.ComputedConnectors = {} + self.ConnectionTypes = {} + self.RelatedConnections = [] self.SFCNetworks = {"Steps":{}, "Transitions":{}, "Actions":{}} self.SFCComputedBlocks = "" self.ActionNumber = 0 @@ -187,22 +243,71 @@ return True return False + def GetVariableType(self, name): + for list_type, retain, constant, located, vars in self.Interface: + for var_type, var_name, var_address, var_initial in vars: + if name == var_name: + return var_type + return None + + def GetConnectedConnection(self, connection, body): + links = connection.getConnections() + if links and len(links) == 1: + return self.GetLinkedConnection(links[0], body) + return None + + def GetLinkedConnection(self, link, body): + parameter = link.getFormalParameter() + instance = body.getContentInstance(link.getRefLocalId()) + if isinstance(instance, (plcopen.inVariable, plcopen.inOutVariable, plcopen.continuation, plcopen.contact, plcopen.coil)): + return instance.connectionPointOut + elif isinstance(instance, plcopen.block): + outputvariables = instance.outputVariables.getVariable() + if len(outputvariables) == 1: + return outputvariables[0].connectionPointOut + elif parameter: + for variable in outputvariables: + if variable.getFormalParameter() == parameter: + return variable.connectionPointOut + else: + point = link.getPosition()[-1] + for variable in outputvariables: + relposition = variable.connectionPointOut.getRelPosition() + blockposition = instance.getPosition() + if point.x == blockposition.x + relposition[0] and point.y == blockposition.y + relposition[1]: + return variable.connectionPointOut + elif isinstance(instance, plcopen.leftPowerRail): + outputconnections = instance.getConnectionPointOut() + if len(outputconnections) == 1: + return outputconnections[0] + else: + point = link.getPosition()[-1] + for outputconnection in outputconnections: + relposition = outputconnection.getRelPosition() + powerrailposition = instance.getPosition() + 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 GenerateInterface(self, interface): if self.Type == "FUNCTION": - self.ReturnType = interface.getReturnType().getValue() + returntype_content = interface.getReturnType().getContent() + if returntype_content["value"] is None: + self.ReturnType = returntype_content["name"] + else: + self.ReturnType = returntype_content["value"].getName() for varlist in interface.getContent(): variables = [] located = False for var in varlist["value"].getVariable(): - type = var.getType().getValue() - if not isinstance(type, (StringType, UnicodeType)): - type = type.getName() - GeneratePouProgram(type) - blocktype = GetBlockType(type) - if blocktype: - variables.extend(blocktype["initialise"](type, var.getName())) - located = False - else: + vartype_content = var.getType().getContent() + if vartype_content["value"] is None: initial = var.getInitialValue() if initial: initial_value = initial.getValue() @@ -211,11 +316,120 @@ address = var.getAddress() if address: located = True - variables.append((type, var.getName(), address, initial_value)) + variables.append((vartype_content["name"], var.getName(), address, initial_value)) + else: + var_type = vartype_content["value"].getName() + GeneratePouProgram(var_type) + blocktype = GetBlockType(var_type) + if blocktype is not None: + variables.extend(blocktype["initialise"](var_type, var.getName())) + located = False + else: + initial = var.getInitialValue() + if initial: + initial_value = initial.getValue() + else: + initial_value = None + address = var.getAddress() + if address: + located = True + variables.append((vartype_content["value"].getName(), var.getName(), address, initial_value)) if len(variables) > 0: self.Interface.append((varTypeNames[varlist["name"]], varlist["value"].getRetain(), varlist["value"].getConstant(), located, variables)) + def GenerateConnectionTypes(self, pou): + body = pou.getBody() + body_content = body.getContent() + body_type = body_content["name"] + if body_type in ["FBD", "LD", "SFC"]: + for instance in body.getContentInstances(): + if isinstance(instance, (plcopen.inVariable, plcopen.outVariable, plcopen.inOutVariable)): + expression = instance.getExpression() + var_type = self.GetVariableType(expression) + if expression == pou.getName(): + returntype_content = pou.interface.getReturnType().getContent() + if returntype_content["value"] is None: + var_type = returntype_content["name"] + else: + var_type = returntype_content["value"].getName() + elif var_type is None: + var_type = expression.split("#")[0] + if isinstance(instance, (plcopen.inVariable, plcopen.inOutVariable)): + self.ConnectionTypes[instance.connectionPointOut] = var_type + if isinstance(instance, (plcopen.outVariable, plcopen.inOutVariable)): + self.ConnectionTypes[instance.connectionPointIn] = var_type + connected = self.GetConnectedConnection(instance.connectionPointIn, body) + if connected and connected not in self.ConnectionTypes: + for connection in self.ExtractRelatedConnections(connected): + self.ConnectionTypes[connection] = var_type + elif isinstance(instance, (plcopen.contact, plcopen.coil)): + self.ConnectionTypes[instance.connectionPointOut] = "BOOL" + self.ConnectionTypes[instance.connectionPointIn] = "BOOL" + connected = self.GetConnectedConnection(instance.connectionPointIn, body) + if connected and connected not in self.ConnectionTypes: + for connection in self.ExtractRelatedConnections(connected): + self.ConnectionTypes[connection] = "BOOL" + elif isinstance(instance, plcopen.leftPowerRail): + for connection in instance.getConnectionPointOut(): + self.ConnectionTypes[connection] = "BOOL" + elif isinstance(instance, plcopen.rightPowerRail): + for connection in instance.getConnectionPointIn(): + self.ConnectionTypes[connection] = "BOOL" + connected = self.GetConnectedConnection(connection, body) + if connected and connected not in self.ConnectionTypes: + for connection in self.ExtractRelatedConnections(connected): + self.ConnectionTypes[connection] = "BOOL" + elif isinstance(instance, plcopen.transition): + content = instance.condition.getContent() + if content["name"] == "connection" and len(content["value"]) == 1: + connected = self.GetLinkedConnection(content["value"][0], body) + if connected and connected not in self.ConnectionTypes: + for connection in self.ExtractRelatedConnections(connected): + self.ConnectionTypes[connection] = "BOOL" + elif isinstance(instance, plcopen.block): + block_infos = GetBlockType(instance.getTypeName()) + undefined = {} + for variable in instance.outputVariables.getVariable(): + output_name = variable.getFormalParameter() + for oname, otype, oqualifier in block_infos["outputs"]: + if output_name == oname and variable.connectionPointOut not in self.ConnectionTypes: + if otype.startswith("ANY"): + if otype not in undefined: + undefined[otype] = [] + undefined[otype].append(variable.connectionPointOut) + else: + for connection in self.ExtractRelatedConnections(variable.connectionPointOut): + self.ConnectionTypes[connection] = otype + for variable in instance.inputVariables.getVariable(): + input_name = variable.getFormalParameter() + for iname, itype, iqualifier in block_infos["inputs"]: + if input_name == iname: + connected = self.GetConnectedConnection(variable.connectionPointIn, body) + if itype.startswith("ANY"): + if itype not in undefined: + undefined[itype] = [] + undefined[itype].append(variable.connectionPointIn) + if connected: + undefined[itype].append(connected) + else: + self.ConnectionTypes[variable.connectionPointIn] = itype + if connected and connected not in self.ConnectionTypes: + for connection in self.ExtractRelatedConnections(connected): + self.ConnectionTypes[connection] = itype + for var_type, connections in undefined.items(): + related = [] + for connection in connections: + if connection in self.ConnectionTypes: + var_type = self.ConnectionTypes[connection] + else: + related.extend(self.ExtractRelatedConnections(connection)) + if var_type.startswith("ANY") and len(related) > 0: + self.RelatedConnections.append(related) + else: + for connection in related: + self.ConnectionTypes[connection] = var_type + def GenerateProgram(self, pou): body = pou.getBody() body_content = body.getContent() @@ -223,7 +437,20 @@ if body_type in ["IL","ST"]: self.Program = ReIndentText(body_content["value"].getText(), 2) elif body_type == "FBD": + orderedInstances = [] + otherInstances = [] for instance in body.getContentInstances(): + if isinstance(instance, (plcopen.outVariable, plcopen.inOutVariable, plcopen.block)): + executionOrderId = instance.getExecutionOrderId() + if executionOrderId > 0: + orderedInstances.append((executionOrderId, instance)) + else: + otherInstances.append(instance) + elif isinstance(instance, plcopen.connector): + otherInstances.append(instance) + orderedInstances.sort() + instances = [instance for (executionOrderId, instance) in orderedInstances] + otherInstances + for instance in instances: if isinstance(instance, (plcopen.outVariable, plcopen.inOutVariable)): var = instance.getExpression() connections = instance.connectionPointIn.getConnections() @@ -231,8 +458,9 @@ expression = self.ComputeFBDExpression(body, connections[0]) self.Program += " %s := %s;\n"%(var, expression) elif isinstance(instance, plcopen.block): - type = instance.getTypeName() - block_infos = GetBlockType(type) + block_type = instance.getTypeName() + self.GeneratePouProgram(block_type) + block_infos = GetBlockType(block_type) block_infos["generate"](self, instance, body, None) elif isinstance(instance, plcopen.connector): connector = instance.getName() @@ -271,15 +499,16 @@ for initialstep in self.InitialSteps: self.ComputeSFCStep(initialstep) - def ComputeFBDExpression(self, body, link): + def ComputeFBDExpression(self, body, link, order = False): localid = link.getRefLocalId() instance = body.getContentInstance(localid) if isinstance(instance, (plcopen.inVariable, plcopen.inOutVariable)): return instance.getExpression() elif isinstance(instance, plcopen.block): block_type = instance.getTypeName() + self.GeneratePouProgram(block_type) block_infos = GetBlockType(block_type) - return block_infos["generate"](self, instance, body, link) + return block_infos["generate"](self, instance, body, link, order) elif isinstance(instance, plcopen.continuation): name = instance.getName() computed_value = self.ComputedConnectors.get(name, None) @@ -290,7 +519,7 @@ if tmp_instance.getName() == name: connections = tmp_instance.connectionPointIn.getConnections() if connections and len(connections) == 1: - expression = self.ComputeFBDExpression(body, connections[0]) + expression = self.ComputeFBDExpression(body, connections[0], order) self.ComputedConnectors[name] = expression return expression raise ValueError, "No connector found" @@ -304,6 +533,7 @@ paths.append(None) elif isinstance(next, plcopen.block): block_type = next.getTypeName() + self.GeneratePouProgram(block_type) block_infos = GetBlockType(block_type) paths.append(block_infos["generate"](self, next, body, connection)) else: @@ -662,8 +892,15 @@ global currentProject, currentProgram currentProject = project currentProgram = "" + for datatype in project.getDataTypes(): + datatypeComputed[datatype.getName()] = False for pou in project.getPous(): pouComputed[pou.getName()] = False + if len(datatypeComputed) > 0: + currentProgram += "TYPE\n" + for datatype_name in datatypeComputed.keys(): + GenerateDataType(datatype_name) + currentProgram += "END_TYPE\n\n" for pou_name in pouComputed.keys(): GeneratePouProgram(pou_name) for config in project.getConfigurations():