diff -r e8c43f542eb1 -r f2cffda17d00 etherlab/etherlab.py --- a/etherlab/etherlab.py Fri Mar 29 01:13:17 2013 +0100 +++ b/etherlab/etherlab.py Fri Mar 29 01:15:01 2013 +0100 @@ -1,1677 +1,17 @@ import os, shutil -import cPickle from xml.dom import minidom import wx import csv from xmlclass import * -from POULibrary import POULibrary + from ConfigTreeNode import ConfigTreeNode from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY -from ConfigEditor import NodeEditor, CIA402NodeEditor, MasterEditor, LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE -from dialogs import BrowseValuesLibraryDialog -from IDEFrame import TITLE, FILEMENU, PROJECTTREE - -try: - from MotionLibrary import Headers, AxisXSD - HAS_MCL = True -except: - HAS_MCL = False - -TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", - "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", - "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"} - -DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64", - "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", - "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"} - -VARCLASSCONVERSION = {"T": LOCATION_VAR_INPUT, "R": LOCATION_VAR_OUTPUT, "RT": LOCATION_VAR_MEMORY} - -#-------------------------------------------------- -# Remote Exec Etherlab Commands -#-------------------------------------------------- - -SCAN_COMMAND = """ -import commands -result = commands.getoutput("ethercat slaves") -slaves = [] -for slave_line in result.splitlines(): - chunks = slave_line.split() - idx, pos, state, flag = chunks[:4] - name = " ".join(chunks[4:]) - alias, position = pos.split(":") - slave = {"idx": int(idx), - "alias": int(alias), - "position": int(position), - "name": name} - details = commands.getoutput("ethercat slaves -p %d -v" % slave["idx"]) - for details_line in details.splitlines(): - details_line = details_line.strip() - for header, param in [("Vendor Id:", "vendor_id"), - ("Product code:", "product_code"), - ("Revision number:", "revision_number")]: - if details_line.startswith(header): - slave[param] = details_line.split()[-1] - break - slaves.append(slave) -returnVal = slaves -""" - -#-------------------------------------------------- -# Etherlab Specific Blocks Library -#-------------------------------------------------- - -def GetLocalPath(filename): - return os.path.join(os.path.split(__file__)[0], filename) - -class EtherlabLibrary(POULibrary): - def GetLibraryPath(self): - return GetLocalPath("pous.xml") - - def Generate_C(self, buildpath, varlist, IECCFLAGS): - etherlab_ext_file = open(GetLocalPath("etherlab_ext.c"), 'r') - etherlab_ext_code = etherlab_ext_file.read() - etherlab_ext_file.close() - - Gen_etherlabfile_path = os.path.join(buildpath, "etherlab_ext.c") - ethelabfile = open(Gen_etherlabfile_path,'w') - ethelabfile.write(etherlab_ext_code) - ethelabfile.close() - - runtimefile_path = os.path.join(os.path.split(__file__)[0], "runtime_etherlab.py") - return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", - ("runtime_etherlab.py", file(GetLocalPath("runtime_etherlab.py")))) - -#-------------------------------------------------- -# Ethercat Node -#-------------------------------------------------- - -class _EthercatSlaveCTN: - - NODE_PROFILE = None - EditorType = NodeEditor - - def GetIconName(self): - return "Slave" - - def ExtractHexDecValue(self, value): - return ExtractHexDecValue(value) - - def GetSizeOfType(self, type): - return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None) - - def GetSlavePos(self): - return self.BaseParams.getIEC_Channel() - - def GetParamsAttributes(self, path = None): - if path: - parts = path.split(".", 1) - if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: - return self.MandatoryParams[1].getElementInfos(parts[0], parts[1]) - elif self.CTNParams and parts[0] == self.CTNParams[0]: - return self.CTNParams[1].getElementInfos(parts[0], parts[1]) - else: - params = [] - if self.CTNParams: - params.append(self.CTNParams[1].getElementInfos(self.CTNParams[0])) - else: - params.append({ - 'use': 'required', - 'type': 'element', - 'name': 'SlaveParams', - 'value': None, - 'children': [] - }) - - slave_type = self.CTNParent.GetSlaveType(self.GetSlavePos()) - params[0]['children'].insert(0, - {'use': 'optional', - 'type': self.CTNParent.GetSlaveTypesLibrary(self.NODE_PROFILE), - 'name': 'Type', - 'value': (slave_type["device_type"], slave_type)}) - params[0]['children'].insert(1, - {'use': 'optional', - 'type': 'unsignedLong', - 'name': 'Alias', - 'value': self.CTNParent.GetSlaveAlias(self.GetSlavePos())}) - return params - - def SetParamsAttribute(self, path, value): - position = self.BaseParams.getIEC_Channel() - - if path == "SlaveParams.Type": - self.CTNParent.SetSlaveType(position, value) - slave_type = self.CTNParent.GetSlaveType(self.GetSlavePos()) - value = (slave_type["device_type"], slave_type) - if self._View is not None: - wx.CallAfter(self._View.RefreshSlaveInfos) - return value, True - elif path == "SlaveParams.Alias": - self.CTNParent.SetSlaveAlias(position, value) - return value, True - - value, refresh = ConfigTreeNode.SetParamsAttribute(self, path, value) - - # Filter IEC_Channel, Slave_Type and Alias that have specific behavior - if path == "BaseParams.IEC_Channel" and value != position: - self.CTNParent.SetSlavePosition(position, value) - - return value, refresh - - def GetSlaveInfos(self): - return self.CTNParent.GetSlaveInfos(self.GetSlavePos()) - - def GetSlaveVariables(self, limits): - return self.CTNParent.GetSlaveVariables(self.GetSlavePos(), limits) - - def GetVariableLocationTree(self): - return {"name": self.BaseParams.getName(), - "type": LOCATION_CONFNODE, - "location": self.GetFullIEC_Channel(), - "children": self.CTNParent.GetDeviceLocationTree(self.GetSlavePos(), self.GetCurrentLocation(), self.BaseParams.getName()) - } - - def CTNGenerate_C(self, buildpath, locations): - return [],"",False - -#-------------------------------------------------- -# Ethercat CIA402 Node -#-------------------------------------------------- - -if HAS_MCL: - - NODE_VARIABLES = [ - ("ControlWord", 0x6040, 0x00, "UINT", "Q"), - ("TargetPosition", 0x607a, 0x00, "DINT", "Q"), - ("ModesOfOperation", 0x06060, 0x00, "SINT", "Q"), - ("StatusWord", 0x6041, 0x00, "UINT", "I"), - ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"), - ("ActualPosition", 0x6064, 0x00, "DINT", "I"), - ("ActualVelocity", 0x606C, 0x00, "DINT", "I"), - ] - - DEFAULT_RETRIEVE = " __CIA402Node_%(location)s.axis->%(name)s = *(__CIA402Node_%(location)s.%(name)s);" - DEFAULT_PUBLISH = " *(__CIA402Node_%(location)s.%(name)s) = __CIA402Node_%(location)s.axis->%(name)s;" - - EXTRA_NODE_VARIABLES = [ - ("ErrorCode", [ - {"description": ("ErrorCode", 0x603F, 0x00, "UINT", "I"), - "publish": None} - ]), - ("DigitalInputs", [ - {"description": ("DigitalInputs", 0x60FD, 0x00, "UDINT", "I"), - "publish": None} - ]), - ("DigitalOutputs", [ - {"description": ("DigitalOutputs", 0x60FE, 0x00, "UDINT", "Q"), - "retrieve": None} - ]) - ] - EXTRA_NODE_VARIABLES_DICT = dict([("Enable" + name, value) for name, value in EXTRA_NODE_VARIABLES]) - - BLOCK_INPUT_TEMPLATE = " __SET_VAR(%(blockname)s->,%(input_name)s, %(input_value)s);" - BLOCK_OUTPUT_TEMPLATE = " __SET_VAR(data__->,%(output_name)s, __GET_VAR(%(blockname)s->%(output_name)s));" - - BLOCK_FUNCTION_TEMPLATE = """ -extern void ETHERLAB%(ucase_blocktype)s_body__(ETHERLAB%(ucase_blocktype)s* data__); -void __%(blocktype)s_%(location)s(MC_%(ucase_blocktype)s *data__) { - __DECLARE_GLOBAL_PROTOTYPE(ETHERLAB%(ucase_blocktype)s, %(blockname)s); - ETHERLAB%(ucase_blocktype)s* %(blockname)s = __GET_GLOBAL_%(blockname)s(); -%(extract_inputs)s - ETHERLAB%(ucase_blocktype)s_body__(%(blockname)s); -%(return_outputs)s -} -""" - - BLOCK_FUNTION_DEFINITION_TEMPLATE = """ if (!__CIA402Node_%(location)s.axis->__mcl_func_MC_%(blocktype)s) - __CIA402Node_%(location)s.axis->__mcl_func_MC_%(blocktype)s = __%(blocktype)s_%(location)s;""" - - GLOBAL_INSTANCES = [ - {"blocktype": "GetTorqueLimit", - "inputs": [], - "outputs": [{"name": "TorqueLimitPos", "type": "UINT"}, - {"name": "TorqueLimitNeg", "type": "UINT"}]}, - {"blocktype": "SetTorqueLimit", - "inputs": [{"name": "TorqueLimitPos", "type": "UINT"}, - {"name": "TorqueLimitNeg", "type": "UINT"}], - "outputs": []}, - ] - - class _EthercatCIA402SlaveCTN(_EthercatSlaveCTN): - XSD = """ - - - - %s - - - - """ % ("\n".join(['' % category - for category, variables in EXTRA_NODE_VARIABLES]) + AxisXSD) - - NODE_PROFILE = 402 - EditorType = CIA402NodeEditor - - ConfNodeMethods = [ - {"bitmap" : "CIA402AxisRef", - "name" : _("Axis Ref"), - "tooltip" : _("Initiate Drag'n drop of Axis ref located variable"), - "method" : "_getCIA402AxisRef", - "push": True}, - ] - - def GetIconName(self): - return "CIA402Slave" - - def SetParamsAttribute(self, path, value): - if path == "CIA402SlaveParams.Type": - path = "SlaveParams.Type" - elif path == "CIA402SlaveParams.Alias": - path = "SlaveParams.Alias" - return _EthercatSlaveCTN.SetParamsAttribute(self, path, value) - - def GetVariableLocationTree(self): - axis_name = self.CTNName() - current_location = self.GetCurrentLocation() - children = [{"name": "%s Axis Ref" % (axis_name), - "type": LOCATION_VAR_INPUT, - "size": "W", - "IEC_type": "AXIS_REF", - "var_name": axis_name, - "location": "%%IW%s.0" % (".".join(map(str, current_location))), - "description": "", - "children": []}] - children.extend(self.CTNParent.GetDeviceLocationTree(self.GetSlavePos(), current_location, axis_name)) - return {"name": axis_name, - "type": LOCATION_CONFNODE, - "location": self.GetFullIEC_Channel(), - "children": children, - } - - def CTNGlobalInstances(self): - current_location = self.GetCurrentLocation() - return [("%s_%s" % (block_infos["blocktype"], "_".join(map(str, current_location))), - "EtherLab%s" % block_infos["blocktype"]) for block_infos in GLOBAL_INSTANCES] - - def _getCIA402AxisRef(self): - data = wx.TextDataObject(str(("%%IW%s.0" % ".".join(map(str, self.GetCurrentLocation())), - "location", "AXIS_REF", self.CTNName(), ""))) - dragSource = wx.DropSource(self.GetCTRoot().AppFrame) - dragSource.SetData(data) - dragSource.DoDragDrop() - - def CTNGenerate_C(self, buildpath, locations): - current_location = self.GetCurrentLocation() - - location_str = "_".join(map(lambda x:str(x), current_location)) - - plc_cia402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_cia402node.c") - plc_cia402node_file = open(plc_cia402node_filepath, 'r') - plc_cia402node_code = plc_cia402node_file.read() - plc_cia402node_file.close() - - str_completion = { - "slave_pos": self.GetSlavePos(), - "location": location_str, - "MCL_headers": Headers, - "extern_located_variables_declaration": [], - "fieldbus_interface_declaration": [], - "fieldbus_interface_definition": [], - "entry_variables": [], - "init_axis_params": [], - "init_entry_variables": [], - "extra_variables_retrieve": [], - "extra_variables_publish": [] - } - - for blocktype_infos in GLOBAL_INSTANCES: - texts = { - "blocktype": blocktype_infos["blocktype"], - "ucase_blocktype": blocktype_infos["blocktype"].upper(), - "location": "_".join(map(str, current_location)) - } - texts["blockname"] = "%(ucase_blocktype)s_%(location)s" % texts - - inputs = [{"input_name": "POS", "input_value": str(self.GetSlavePos())}, - {"input_name": "EXECUTE", "input_value": "__GET_VAR(data__->EXECUTE)"}] +\ - [{"input_name": input["name"].upper(), - "input_value": "__GET_VAR(data__->%s)" % input["name"].upper()} - for input in blocktype_infos["inputs"]] - input_texts = [] - for input_infos in inputs: - input_infos.update(texts) - input_texts.append(BLOCK_INPUT_TEMPLATE % input_infos) - texts["extract_inputs"] = "\n".join(input_texts) - - outputs = [{"output_name": output} for output in ["DONE", "BUSY", "ERROR"]] + \ - [{"output_name": output["name"].upper()} for output in blocktype_infos["outputs"]] - output_texts = [] - for output_infos in outputs: - output_infos.update(texts) - output_texts.append(BLOCK_OUTPUT_TEMPLATE % output_infos) - texts["return_outputs"] = "\n".join(output_texts) - - str_completion["fieldbus_interface_declaration"].append( - BLOCK_FUNCTION_TEMPLATE % texts) - - str_completion["fieldbus_interface_definition"].append( - BLOCK_FUNTION_DEFINITION_TEMPLATE % texts) - - variables = NODE_VARIABLES[:] - - params = self.CTNParams[1].getElementInfos(self.CTNParams[0]) - for param in params["children"]: - if param["name"] in EXTRA_NODE_VARIABLES_DICT: - if param["value"]: - extra_variables = EXTRA_NODE_VARIABLES_DICT.get(param["name"]) - for variable_infos in extra_variables: - var_infos = { - "location": location_str, - "name": variable_infos["description"][0] - } - variables.append(variable_infos["description"]) - retrieve_template = variable_infos.get("retrieve", DEFAULT_RETRIEVE) - publish_template = variable_infos.get("publish", DEFAULT_PUBLISH) - - if retrieve_template is not None: - str_completion["extra_variables_retrieve"].append( - retrieve_template % var_infos) - if publish_template is not None: - str_completion["extra_variables_publish"].append( - publish_template % var_infos) - elif param["value"] is not None: - param_infos = { - "location": location_str, - "param_name": param["name"], - } - if param["type"] == "boolean": - param_infos["param_value"] = {True: "true", False: "false"}[param["value"]] - else: - param_infos["param_value"] = str(param["value"]) - str_completion["init_axis_params"].append( - " __CIA402Node_%(location)s.axis->%(param_name)s = %(param_value)s;" % param_infos) - - for variable in variables: - var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable)) - var_infos["location"] = location_str - var_infos["var_size"] = self.GetSizeOfType(var_infos["var_type"]) - var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos - - str_completion["extern_located_variables_declaration"].append( - "IEC_%(var_type)s *%(var_name)s;" % var_infos) - str_completion["entry_variables"].append( - " IEC_%(var_type)s *%(name)s;" % var_infos) - str_completion["init_entry_variables"].append( - " __CIA402Node_%(location)s.%(name)s = %(var_name)s;" % var_infos) - - self.CTNParent.FileGenerator.DeclareVariable( - self.GetSlavePos(), var_infos["index"], var_infos["subindex"], - var_infos["var_type"], var_infos["dir"], var_infos["var_name"]) - - for element in ["extern_located_variables_declaration", - "fieldbus_interface_declaration", - "fieldbus_interface_definition", - "entry_variables", - "init_axis_params", - "init_entry_variables", - "extra_variables_retrieve", - "extra_variables_publish"]: - str_completion[element] = "\n".join(str_completion[element]) - - Gen_CIA402Nodefile_path = os.path.join(buildpath, "cia402node_%s.c"%location_str) - cia402nodefile = open(Gen_CIA402Nodefile_path, 'w') - cia402nodefile.write(plc_cia402node_code % str_completion) - cia402nodefile.close() - - return [(Gen_CIA402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))],"",True - -#-------------------------------------------------- -# Ethercat MASTER -#-------------------------------------------------- - -EtherCATConfigClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATConfig.xsd")) - -def ExtractHexDecValue(value): - try: - return int(value) - except: - pass - try: - return int(value.replace("#", "0"), 16) - except: - raise ValueError, "Invalid value for HexDecValue \"%s\"" % value - -def GenerateHexDecValue(value, base=10): - if base == 10: - return str(value) - elif base == 16: - return "#x%.8x" % value - else: - raise ValueError, "Not supported base" - -def sort_commands(x, y): - if x["Index"] == y["Index"]: - return cmp(x["Subindex"], y["Subindex"]) - return cmp(x["Index"], y["Index"]) - -cls = EtherCATConfigClasses.get("Config_Slave", None) -if cls: - - def getType(self): - slave_info = self.getInfo() - return {"device_type": slave_info.getName(), - "vendor": GenerateHexDecValue(slave_info.getVendorId()), - "product_code": GenerateHexDecValue(slave_info.getProductCode(), 16), - "revision_number": GenerateHexDecValue(slave_info.getRevisionNo(), 16)} - setattr(cls, "getType", getType) - - def setType(self, type_infos): - slave_info = self.getInfo() - slave_info.setName(type_infos["device_type"]) - slave_info.setVendorId(ExtractHexDecValue(type_infos["vendor"])) - slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"])) - slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"])) - setattr(cls, "setType", setType) - - def getInitCmds(self, create_default=False): - Mailbox = self.getMailbox() - if Mailbox is None: - if create_default: - self.addMailbox() - Mailbox = self.getMailbox() - else: - return None - CoE = Mailbox.getCoE() - if CoE is None: - if create_default: - Mailbox.addCoE() - CoE = Mailbox.getCoE() - else: - return None - InitCmds = CoE.getInitCmds() - if InitCmds is None and create_default: - CoE.addInitCmds() - InitCmds = CoE.getInitCmds() - return InitCmds - setattr(cls, "getInitCmds", getInitCmds) - - def getStartupCommands(self): - pos = self.getInfo().getPhysAddr() - InitCmds = self.getInitCmds() - if InitCmds is None: - return [] - commands = [] - for idx, InitCmd in enumerate(InitCmds.getInitCmd()): - comment = InitCmd.getComment() - if comment is None: - comment = "" - commands.append({ - "command_idx": idx, - "Position": pos, - "Index": InitCmd.getIndex(), - "Subindex": InitCmd.getSubIndex(), - "Value": InitCmd.getData(), - "Description": comment}) - commands.sort(sort_commands) - return commands - setattr(cls, "getStartupCommands", getStartupCommands) - - def appendStartupCommand(self, command_infos): - InitCmds = self.getInitCmds(True) - command = EtherCATConfigClasses["InitCmds_InitCmd"]() - command.setIndex(command_infos["Index"]) - command.setSubIndex(command_infos["Subindex"]) - command.setData(command_infos["Value"]) - command.setComment(command_infos["Description"]) - InitCmds.appendInitCmd(command) - return len(InitCmds.getInitCmd()) - 1 - setattr(cls, "appendStartupCommand", appendStartupCommand) - - def setStartupCommand(self, command_infos): - InitCmds = self.getInitCmds() - if InitCmds is not None: - commands = InitCmds.getInitCmd() - if command_infos["command_idx"] < len(commands): - command = commands[command_infos["command_idx"]] - command.setIndex(command_infos["Index"]) - command.setSubIndex(command_infos["Subindex"]) - command.setData(command_infos["Value"]) - command.setComment(command_infos["Description"]) - setattr(cls, "setStartupCommand", setStartupCommand) - - def removeStartupCommand(self, command_idx): - InitCmds = self.getInitCmds() - if InitCmds is not None: - if command_idx < len(InitCmds.getInitCmd()): - InitCmds.removeInitCmd(command_idx) - setattr(cls, "removeStartupCommand", removeStartupCommand) - -ProcessVariablesXSD = """ - - - - - - - - - - - - - - - - - - - - - - - -""" - -ProcessVariablesClasses = GenerateClassesFromXSDstring(ProcessVariablesXSD) - -class _EthercatCTN: - - CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")] - if HAS_MCL: - CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave")) - EditorType = MasterEditor - - def __init__(self): - config_filepath = self.ConfigFileName() - config_is_saved = False - self.Config = EtherCATConfigClasses["EtherCATConfig"]() - if os.path.isfile(config_filepath): - config_xmlfile = open(config_filepath, 'r') - config_tree = minidom.parse(config_xmlfile) - config_xmlfile.close() - - for child in config_tree.childNodes: - if child.nodeType == config_tree.ELEMENT_NODE and child.nodeName == "EtherCATConfig": - self.Config.loadXMLTree(child) - config_is_saved = True - - process_filepath = self.ProcessVariablesFileName() - process_is_saved = False - self.ProcessVariables = ProcessVariablesClasses["ProcessVariables"]() - if os.path.isfile(process_filepath): - process_xmlfile = open(process_filepath, 'r') - process_tree = minidom.parse(process_xmlfile) - process_xmlfile.close() - - for child in process_tree.childNodes: - if child.nodeType == process_tree.ELEMENT_NODE and child.nodeName == "ProcessVariables": - self.ProcessVariables.loadXMLTree(child) - process_is_saved = True - - if config_is_saved and process_is_saved: - self.CreateBuffer(True) - else: - self.CreateBuffer(False) - self.OnCTNSave() - - def GetContextualMenuItems(self): - return [("Add Ethercat Slave", "Add Ethercat Slave to Master", self.OnAddEthercatSlave)] - - def OnAddEthercatSlave(self, event): - app_frame = self.GetCTRoot().AppFrame - dialog = BrowseValuesLibraryDialog(app_frame, - "Ethercat Slave Type", self.GetSlaveTypesLibrary()) - if dialog.ShowModal() == wx.ID_OK: - type_infos = dialog.GetValueInfos() - device, alignment = self.GetModuleInfos(type_infos) - if device is not None: - if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): - ConfNodeType = "EthercatCIA402Slave" - else: - ConfNodeType = "EthercatSlave" - new_child = self.CTNAddChild("%s_0" % ConfNodeType, ConfNodeType) - new_child.SetParamsAttribute("SlaveParams.Type", type_infos) - self.CTNRequestSave() - new_child._OpenView() - app_frame._Refresh(TITLE, FILEMENU, PROJECTTREE) - dialog.Destroy() - - def ExtractHexDecValue(self, value): - return ExtractHexDecValue(value) - - def GetSizeOfType(self, type): - return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None) - - def ConfigFileName(self): - return os.path.join(self.CTNPath(), "config.xml") - - def ProcessVariablesFileName(self): - return os.path.join(self.CTNPath(), "process_variables.xml") - - def FilterSlave(self, slave, vendor=None, slave_pos=None, slave_profile=None): - if slave_pos is not None and slave.getInfo().getPhysAddr() != slave_pos: - return False - type_infos = slave.getType() - if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: - return False - device, alignment = self.GetModuleInfos(type_infos) - if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): - return False - return True - - def GetSlaves(self, vendor=None, slave_pos=None, slave_profile=None): - slaves = [] - for slave in self.Config.getConfig().getSlave(): - if self.FilterSlave(slave, vendor, slave_pos, slave_profile): - slaves.append(slave.getInfo().getPhysAddr()) - slaves.sort() - return slaves - - def GetSlave(self, slave_pos): - for slave in self.Config.getConfig().getSlave(): - slave_info = slave.getInfo() - if slave_info.getPhysAddr() == slave_pos: - return slave - return None - - def GetStartupCommands(self, vendor=None, slave_pos=None, slave_profile=None): - commands = [] - for slave in self.Config.getConfig().getSlave(): - if self.FilterSlave(slave, vendor, slave_pos, slave_profile): - commands.append((slave.getInfo().getPhysAddr(), slave.getStartupCommands())) - commands.sort() - return reduce(lambda x, y: x + y[1], commands, []) - - def AppendStartupCommand(self, command_infos): - slave = self.GetSlave(command_infos["Position"]) - if slave is not None: - command_idx = slave.appendStartupCommand(command_infos) - self.BufferModel() - return command_idx - return None - - def SetStartupCommandInfos(self, command_infos): - slave = self.GetSlave(command_infos["Position"]) - if slave is not None: - slave.setStartupCommand(command_infos) - self.BufferModel() - - def RemoveStartupCommand(self, slave_pos, command_idx, buffer=True): - slave = self.GetSlave(slave_pos) - if slave is not None: - slave.removeStartupCommand(command_idx) - if buffer: - self.BufferModel() - - def SetProcessVariables(self, variables): - vars = [] - for var in variables: - variable = ProcessVariablesClasses["ProcessVariables_variable"]() - variable.setName(var["Name"]) - variable.setComment(var["Description"]) - if var["ReadFrom"] != "": - position, index, subindex = var["ReadFrom"] - if variable.getReadFrom() is None: - variable.addReadFrom() - read_from = variable.getReadFrom() - read_from.setPosition(position) - read_from.setIndex(index) - read_from.setSubIndex(subindex) - elif variable.getReadFrom() is not None: - variable.deleteReadFrom() - if var["WriteTo"] != "": - position, index, subindex = var["WriteTo"] - if variable.getWriteTo() is None: - variable.addWriteTo() - write_to = variable.getWriteTo() - write_to.setPosition(position) - write_to.setIndex(index) - write_to.setSubIndex(subindex) - elif variable.getWriteTo() is not None: - variable.deleteWriteTo() - vars.append(variable) - self.ProcessVariables.setvariable(vars) - self.BufferModel() - - def GetProcessVariables(self): - variables = [] - idx = 0 - for variable in self.ProcessVariables.getvariable(): - var = {"Name": variable.getName(), - "Number": idx, - "Description": variable.getComment()} - read_from = variable.getReadFrom() - if read_from is not None: - var["ReadFrom"] = (read_from.getPosition(), - read_from.getIndex(), - read_from.getSubIndex()) - else: - var["ReadFrom"] = "" - write_to = variable.getWriteTo() - if write_to is not None: - var["WriteTo"] = (write_to.getPosition(), - write_to.getIndex(), - write_to.getSubIndex()) - else: - var["WriteTo"] = "" - variables.append(var) - idx += 1 - return variables - - def _ScanNetwork(self): - app_frame = self.GetCTRoot().AppFrame - - execute = True - if len(self.Children) > 0: - dialog = wx.MessageDialog(app_frame, - _("The current network configuration will be deleted.\nDo you want to continue?"), - _("Scan Network"), - wx.YES_NO|wx.ICON_QUESTION) - execute = dialog.ShowModal() == wx.ID_YES - dialog.Destroy() - - if execute: - error, returnVal = self.RemoteExec(SCAN_COMMAND, returnVal = None) - if error != 0: - dialog = wx.MessageDialog(app_frame, returnVal, "Error", wx.OK|wx.ICON_ERROR) - dialog.ShowModal() - dialog.Destroy() - elif returnVal is not None: - for child in self.IECSortedChildren(): - self._doRemoveChild(child) - - for slave in returnVal: - type_infos = { - "vendor": slave["vendor_id"], - "product_code": slave["product_code"], - "revision_number":slave["revision_number"], - } - device, alignment = self.GetModuleInfos(type_infos) - if device is not None: - if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): - CTNType = "EthercatCIA402Slave" - else: - CTNType = "EthercatSlave" - self.CTNAddChild("slave%s" % slave["idx"], CTNType, slave["idx"]) - self.SetSlaveAlias(slave["idx"], slave["alias"]) - type_infos["device_type"] = device.getType().getcontent() - self.SetSlaveType(slave["idx"], type_infos) - - def CTNAddChild(self, CTNName, CTNType, IEC_Channel=0): - """ - Create the confnodes that may be added as child to this node self - @param CTNType: string desining the confnode class name (get name from CTNChildrenTypes) - @param CTNName: string for the name of the confnode instance - """ - newConfNodeOpj = ConfigTreeNode.CTNAddChild(self, CTNName, CTNType, IEC_Channel) - - slave = self.GetSlave(newConfNodeOpj.BaseParams.getIEC_Channel()) - if slave is None: - slave = EtherCATConfigClasses["Config_Slave"]() - slave_infos = slave.getInfo() - slave_infos.setName("undefined") - slave_infos.setPhysAddr(newConfNodeOpj.BaseParams.getIEC_Channel()) - slave_infos.setAutoIncAddr(0) - self.Config.getConfig().appendSlave(slave) - self.BufferModel() - self.OnCTNSave() - - return newConfNodeOpj - - def _doRemoveChild(self, CTNInstance): - slave_pos = CTNInstance.GetSlavePos() - config = self.Config.getConfig() - for idx, slave in enumerate(config.getSlave()): - slave_infos = slave.getInfo() - if slave_infos.getPhysAddr() == slave_pos: - config.removeSlave(idx) - self.BufferModel() - self.OnCTNSave() - ConfigTreeNode._doRemoveChild(self, CTNInstance) - - def SetSlavePosition(self, slave_pos, new_pos): - slave = self.GetSlave(slave_pos) - if slave is not None: - slave_info = slave.getInfo() - slave_info.setPhysAddr(new_pos) - for variable in self.ProcessVariables.getvariable(): - read_from = variable.getReadFrom() - if read_from is not None and read_from.getPosition() == slave_pos: - read_from.setPosition(new_pos) - write_to = variable.getWriteTo() - if write_to is not None and write_to.getPosition() == slave_pos: - write_to.setPosition(new_pos) - self.CreateBuffer(True) - self.OnCTNSave() - if self._View is not None: - self._View.RefreshView() - self._View.RefreshBuffer() - - def GetSlaveAlias(self, slave_pos): - slave = self.GetSlave(slave_pos) - if slave is not None: - slave_info = slave.getInfo() - return slave_info.getAutoIncAddr() - return None - - def SetSlaveAlias(self, slave_pos, alias): - slave = self.GetSlave(slave_pos) - if slave is not None: - slave_info = slave.getInfo() - slave_info.setAutoIncAddr(alias) - self.BufferModel() - - def GetSlaveType(self, slave_pos): - slave = self.GetSlave(slave_pos) - if slave is not None: - return slave.getType() - return None - - def SetSlaveType(self, slave_pos, type_infos): - slave = self.GetSlave(slave_pos) - if slave is not None: - slave.setType(type_infos) - self.BufferModel() - - def GetSlaveInfos(self, slave_pos): - slave = self.GetSlave(slave_pos) - if slave is not None: - type_infos = slave.getType() - device, alignment = self.GetModuleInfos(type_infos) - if device is not None: - infos = type_infos.copy() - infos.update({"physics": device.getPhysics(), - "sync_managers": device.GetSyncManagers(), - "entries": self.GetSlaveVariables(device)}) - return infos - return None - - def GetSlaveVariables(self, slave_pos=None, limits=None, device=None): - if device is None and slave_pos is not None: - slave = self.GetSlave(slave_pos) - if slave is not None: - type_infos = slave.getType() - device, alignment = self.GetModuleInfos(type_infos) - if device is not None: - entries = device.GetEntriesList(limits) - entries_list = entries.items() - entries_list.sort() - entries = [] - current_index = None - current_entry = None - for (index, subindex), entry in entries_list: - entry["children"] = [] - if slave_pos is not None: - entry["Position"] = str(slave_pos) - entry - if index != current_index: - current_index = index - current_entry = entry - entries.append(entry) - elif current_entry is not None: - current_entry["children"].append(entry) - else: - entries.append(entry) - return entries - return [] - - def GetSlaveVariableDataType(self, slave_pos, index, subindex): - slave = self.GetSlave(slave_pos) - if slave is not None: - device, alignment = self.GetModuleInfos(slave.getType()) - if device is not None: - entries = device.GetEntriesList() - entry_infos = entries.get((index, subindex)) - if entry_infos is not None: - return entry_infos["Type"] - return None - - def GetNodesVariables(self, vendor=None, slave_pos=None, slave_profile=None, limits=None): - entries = [] - for slave_position in self.GetSlaves(): - if slave_pos is not None and slave_position != slave_pos: - continue - slave = self.GetSlave(slave_position) - type_infos = slave.getType() - if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: - continue - device, alignment = self.GetModuleInfos(type_infos) - if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): - continue - entries.extend(self.GetSlaveVariables(slave_position, limits, device)) - return entries - - def GetModuleInfos(self, type_infos): - return self.CTNParent.GetModuleInfos(type_infos) - - def GetSlaveTypesLibrary(self, profile_filter=None): - return self.CTNParent.GetModulesLibrary(profile_filter) - - def GetLibraryVendors(self): - return self.CTNParent.GetVendors() - - def GetDeviceLocationTree(self, slave_pos, current_location, device_name): - slave = self.GetSlave(slave_pos) - vars = [] - if slave is not None: - type_infos = slave.getType() - - device, alignment = self.GetModuleInfos(type_infos) - if device is not None: - sync_managers = [] - for sync_manager in device.getSm(): - sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) - sync_manager_direction = sync_manager_control_byte & 0x0c - if sync_manager_direction: - sync_managers.append(LOCATION_VAR_OUTPUT) - else: - sync_managers.append(LOCATION_VAR_INPUT) - - entries = device.GetEntriesList().items() - entries.sort() - for (index, subindex), entry in entries: - var_size = self.GetSizeOfType(entry["Type"]) - if var_size is not None: - var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None) - if var_class is not None: - if var_class == LOCATION_VAR_INPUT: - var_dir = "%I" - else: - var_dir = "%Q" - - vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]), - "type": var_class, - "size": var_size, - "IEC_type": entry["Type"], - "var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex), - "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + - (index, subindex)))), - "description": "", - "children": []}) - - return vars - - def CTNTestModified(self): - return self.ChangesToSave or not self.ModelIsSaved() - - def OnCTNSave(self): - config_filepath = self.ConfigFileName() - - config_text = "\n" - config_extras = {"xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", - "xsi:noNamespaceSchemaLocation" : "EtherCATInfo.xsd"} - config_text += self.Config.generateXMLText("EtherCATConfig", 0, config_extras) - - config_xmlfile = open(config_filepath,"w") - config_xmlfile.write(config_text.encode("utf-8")) - config_xmlfile.close() - - process_filepath = self.ProcessVariablesFileName() - - process_text = "\n" - process_extras = {"xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance"} - process_text += self.ProcessVariables.generateXMLText("ProcessVariables", 0, process_extras) - - process_xmlfile = open(process_filepath,"w") - process_xmlfile.write(process_text.encode("utf-8")) - process_xmlfile.close() - - self.Buffer.CurrentSaved() - return True - - def GetProcessVariableName(self, location, var_type): - return "__M%s_%s" % (self.GetSizeOfType(var_type), "_".join(map(str, location))) - - def _Generate_C(self, buildpath, locations): - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - location_str = "_".join(map(lambda x:str(x), current_location)) - - Gen_Ethercatfile_path = os.path.join(buildpath, "ethercat_%s.c"%location_str) - - self.FileGenerator = _EthercatCFileGenerator(self) - - LocationCFilesAndCFLAGS, LDFLAGS, extra_files = ConfigTreeNode._Generate_C(self, buildpath, locations) - - for idx, variable in enumerate(self.ProcessVariables.getvariable()): - name = None - var_type = None - read_from = variable.getReadFrom() - write_to = variable.getWriteTo() - if read_from is not None: - pos = read_from.getPosition() - index = read_from.getIndex() - subindex = read_from.getSubIndex() - location = current_location + (idx, ) - var_type = self.GetSlaveVariableDataType(pos, index, subindex) - name = self.FileGenerator.DeclareVariable( - pos, index, subindex, var_type, "I", - self.GetProcessVariableName(location, var_type)) - if write_to is not None: - pos = write_to.getPosition() - index = write_to.getIndex() - subindex = write_to.getSubIndex() - if name is None: - location = current_location + (idx, ) - var_type = self.GetSlaveVariableDataType(pos, index, subindex) - name = self.GetProcessVariableName(location, var_type) - self.FileGenerator.DeclareVariable( - pos, index, subindex, var_type, "Q", name, True) - - self.FileGenerator.GenerateCFile(Gen_Ethercatfile_path, location_str, self.BaseParams.getIEC_Channel()) - - LocationCFilesAndCFLAGS.append( - (current_location, - [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))], - True)) - LDFLAGS.append("-lethercat -lrtdm") - - return LocationCFilesAndCFLAGS, LDFLAGS, extra_files - - ConfNodeMethods = [ - {"bitmap" : "ScanNetwork", - "name" : _("Scan Network"), - "tooltip" : _("Scan Network"), - "method" : "_ScanNetwork"}, - ] - - def CTNGenerate_C(self, buildpath, locations): - current_location = self.GetCurrentLocation() - - slaves = self.GetSlaves() - for slave_pos in slaves: - slave = self.GetSlave(slave_pos) - if slave is not None: - self.FileGenerator.DeclareSlave(slave_pos, slave) - - for location in locations: - loc = location["LOC"][len(current_location):] - slave_pos = loc[0] - if slave_pos in slaves and len(loc) == 3 and location["DIR"] != "M": - self.FileGenerator.DeclareVariable( - slave_pos, loc[1], loc[2], location["IEC_TYPE"], location["DIR"], location["NAME"]) - - return [],"",False - -#------------------------------------------------------------------------------- -# Current Buffering Management Functions -#------------------------------------------------------------------------------- - - """ - Return a copy of the config - """ - def Copy(self, model): - return cPickle.loads(cPickle.dumps(model)) - - def CreateBuffer(self, saved): - self.Buffer = UndoBuffer(cPickle.dumps((self.Config, self.ProcessVariables)), saved) - - def BufferModel(self): - self.Buffer.Buffering(cPickle.dumps((self.Config, self.ProcessVariables))) - - def ModelIsSaved(self): - if self.Buffer is not None: - return self.Buffer.IsCurrentSaved() - else: - return True - - def LoadPrevious(self): - self.Config, self.ProcessVariables = cPickle.loads(self.Buffer.Previous()) - - def LoadNext(self): - self.Config, self.ProcessVariables = cPickle.loads(self.Buffer.Next()) - - def GetBufferState(self): - first = self.Buffer.IsFirst() - last = self.Buffer.IsLast() - return not first, not last - - -SLAVE_PDOS_CONFIGURATION_DECLARATION = """ -/* Slave %(slave)d, "%(device_type)s" - * Vendor ID: 0x%(vendor).8x - * Product code: 0x%(product_code).8x - * Revision number: 0x%(revision_number).8x - */ - -ec_pdo_entry_info_t slave_%(slave)d_pdo_entries[] = { -%(pdos_entries_infos)s -}; - -ec_pdo_info_t slave_%(slave)d_pdos[] = { -%(pdos_infos)s -}; - -ec_sync_info_t slave_%(slave)d_syncs[] = { -%(pdos_sync_infos)s - {0xff} -}; -""" - -SLAVE_CONFIGURATION_TEMPLATE = """ - if (!(slave%(slave)d = ecrt_master_slave_config(master, %(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x))) { - SLOGF(LOG_CRITICAL, "Failed to get slave %(device_type)s configuration at alias %(alias)d and position %(position)d.\\n"); - return -1; - } - - if (ecrt_slave_config_pdos(slave%(slave)d, EC_END, slave_%(slave)d_syncs)) { - SLOGF(LOG_CRITICAL, "Failed to configure PDOs for slave %(device_type)s at alias %(alias)d and position %(position)d.\\n"); - return -1; - } -""" - -SLAVE_INITIALIZATION_TEMPLATE = """ - { - uint8_t value[%(data_size)d]; - EC_WRITE_%(data_type)s((uint8_t *)value, %(data)s); - if (ecrt_master_sdo_download(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &abort_code)) { - SLOGF(LOG_CRITICAL, "Failed to initialize slave %(device_type)s at alias %(alias)d and position %(position)d.\\nError: %%d\\n", abort_code); - return -1; - } - } -""" - -SLAVE_OUTPUT_PDO_DEFAULT_VALUE = """ - { - uint8_t value[%(data_size)d]; - if (ecrt_master_sdo_upload(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &result_size, &abort_code)) { - SLOGF(LOG_CRITICAL, "Failed to get default value for output PDO in slave %(device_type)s at alias %(alias)d and position %(position)d.\\nError: %%ud\\n", abort_code); - return -1; - } - %(real_var)s = EC_READ_%(data_type)s((uint8_t *)value); - } -""" - -def ConfigureVariable(entry_infos, str_completion): - entry_infos["data_type"] = DATATYPECONVERSION.get(entry_infos["var_type"], None) - if entry_infos["data_type"] is None: - raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"] - - if not entry_infos.get("no_decl", False): - if entry_infos.has_key("real_var"): - str_completion["located_variables_declaration"].append( - "IEC_%(var_type)s %(real_var)s;" % entry_infos) - else: - entry_infos["real_var"] = "beremiz" + entry_infos["var_name"] - str_completion["located_variables_declaration"].extend( - ["IEC_%(var_type)s %(real_var)s;" % entry_infos, - "IEC_%(var_type)s *%(var_name)s = &%(real_var)s;" % entry_infos]) - for declaration in entry_infos.get("extra_declarations", []): - entry_infos["extra_decl"] = declaration - str_completion["located_variables_declaration"].append( - "IEC_%(var_type)s *%(extra_decl)s = &%(real_var)s;" % entry_infos) - elif not entry_infos.has_key("real_var"): - entry_infos["real_var"] = "beremiz" + entry_infos["var_name"] - - str_completion["used_pdo_entry_offset_variables_declaration"].append( - "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos) - - if entry_infos["data_type"] == "BIT": - str_completion["used_pdo_entry_offset_variables_declaration"].append( - "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos) - - str_completion["used_pdo_entry_configuration"].append( - (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + - "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + - "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos) - - if entry_infos["dir"] == "I": - str_completion["retrieve_variables"].append( - (" %(real_var)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + - "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos) - elif entry_infos["dir"] == "Q": - str_completion["publish_variables"].append( - (" EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + - "slave%(slave)d_%(index).4x_%(subindex).2x_bit, %(real_var)s);") % entry_infos) - - else: - str_completion["used_pdo_entry_configuration"].append( - (" {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + - "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos) - - if entry_infos["dir"] == "I": - str_completion["retrieve_variables"].append( - (" %(real_var)s = EC_READ_%(data_type)s(domain1_pd + " + - "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos) - elif entry_infos["dir"] == "Q": - str_completion["publish_variables"].append( - (" EC_WRITE_%(data_type)s(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + - "%(real_var)s);") % entry_infos) - -def ExclusionSortFunction(x, y): - if x["matching"] == y["matching"]: - if x["assigned"] and not y["assigned"]: - return -1 - elif not x["assigned"] and y["assigned"]: - return 1 - return cmp(x["count"], y["count"]) - return -cmp(x["matching"], y["matching"]) - -class _EthercatCFileGenerator: - - def __init__(self, controler): - self.Controler = controler - - self.Slaves = [] - self.UsedVariables = {} - - def __del__(self): - self.Controler = None - - def DeclareSlave(self, slave_index, slave): - self.Slaves.append((slave_index, slave.getInfo().getAutoIncAddr(), slave)) - - def DeclareVariable(self, slave_index, index, subindex, iec_type, dir, name, no_decl=False): - slave_variables = self.UsedVariables.setdefault(slave_index, {}) - - entry_infos = slave_variables.get((index, subindex), None) - if entry_infos is None: - slave_variables[(index, subindex)] = { - "infos": (iec_type, dir, name, no_decl, []), - "mapped": False} - return name - elif entry_infos["infos"][:2] == (iec_type, dir): - if name != entry_infos["infos"][2]: - if dir == "I": - entry_infos["infos"][3].append(name) - return entry_infos["infos"][2] - else: - raise ValueError, _("Output variables can't be defined with different locations (%s and %s)") % (entry_infos["infos"][2], name) - else: - raise ValueError, _("Definition conflict for location \"%s\"") % name - - def GenerateCFile(self, filepath, location_str, master_number): - - # Extract etherlab master code template - plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c") - plc_etherlab_file = open(plc_etherlab_filepath, 'r') - plc_etherlab_code = plc_etherlab_file.read() - plc_etherlab_file.close() - - # Initialize strings for formatting master code template - str_completion = { - "location": location_str, - "master_number": master_number, - "located_variables_declaration": [], - "used_pdo_entry_offset_variables_declaration": [], - "used_pdo_entry_configuration": [], - "pdos_configuration_declaration": "", - "slaves_declaration": "", - "slaves_configuration": "", - "slaves_output_pdos_default_values_extraction": "", - "slaves_initialization": "", - "retrieve_variables": [], - "publish_variables": [], - } - - # Initialize variable storing variable mapping state - for slave_entries in self.UsedVariables.itervalues(): - for entry_infos in slave_entries.itervalues(): - entry_infos["mapped"] = False - - # Sort slaves by position (IEC_Channel) - self.Slaves.sort() - # Initialize dictionary storing alias auto-increment position values - alias = {} - - # Generating code for each slave - for (slave_idx, slave_alias, slave) in self.Slaves: - type_infos = slave.getType() - - # Defining slave alias and auto-increment position - if alias.get(slave_alias) is not None: - alias[slave_alias] += 1 - else: - alias[slave_alias] = 0 - slave_pos = (slave_alias, alias[slave_alias]) - - # Extract slave device informations - device, alignment = self.Controler.GetModuleInfos(type_infos) - if device is not None: - - # Extract slaves variables to be mapped - slave_variables = self.UsedVariables.get(slave_idx, {}) - - # Extract slave device object dictionary entries - device_entries = device.GetEntriesList() - - # Adding code for declaring slave in master code template strings - for element in ["vendor", "product_code", "revision_number"]: - type_infos[element] = ExtractHexDecValue(type_infos[element]) - type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos))) - - # Extract slave device CoE informations - device_coe = device.getCoE() - if device_coe is not None: - - # If device support CanOpen over Ethernet, adding code for calling - # init commands when initializing slave in master code template strings - initCmds = [] - for initCmd in device_coe.getInitCmd(): - initCmds.append({ - "Index": ExtractHexDecValue(initCmd.getIndex()), - "Subindex": ExtractHexDecValue(initCmd.getSubIndex()), - "Value": initCmd.getData().getcontent()}) - initCmds.extend(slave.getStartupCommands()) - for initCmd in initCmds: - index = initCmd["Index"] - subindex = initCmd["Subindex"] - entry = device_entries.get((index, subindex), None) - if entry is not None: - data_size = entry["BitSize"] / 8 - data_str = ("0x%%.%dx" % (data_size * 2)) % initCmd["Value"] - init_cmd_infos = { - "index": index, - "subindex": subindex, - "data": data_str, - "data_type": DATATYPECONVERSION.get(entry["Type"]), - "data_size": data_size - } - init_cmd_infos.update(type_infos) - str_completion["slaves_initialization"] += SLAVE_INITIALIZATION_TEMPLATE % init_cmd_infos - - # Extract slave device PDO configuration capabilities - PdoAssign = device_coe.getPdoAssign() - PdoConfig = device_coe.getPdoConfig() - else: - PdoAssign = PdoConfig = False - - # Test if slave has a configuration or need one - if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 and PdoConfig and PdoAssign: - - str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos - str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos - - # Initializing - pdos_infos = { - "pdos_entries_infos": [], - "pdos_infos": [], - "pdos_sync_infos": [], - } - pdos_infos.update(type_infos) - - sync_managers = [] - for sync_manager_idx, sync_manager in enumerate(device.getSm()): - sync_manager_infos = { - "index": sync_manager_idx, - "name": sync_manager.getcontent(), - "slave": slave_idx, - "pdos": [], - "pdos_number": 0, - } - - sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) - sync_manager_direction = sync_manager_control_byte & 0x0c - sync_manager_watchdog = sync_manager_control_byte & 0x40 - if sync_manager_direction: - sync_manager_infos["sync_manager_type"] = "EC_DIR_OUTPUT" - else: - sync_manager_infos["sync_manager_type"] = "EC_DIR_INPUT" - if sync_manager_watchdog: - sync_manager_infos["watchdog"] = "EC_WD_ENABLE" - else: - sync_manager_infos["watchdog"] = "EC_WD_DISABLE" - - sync_managers.append(sync_manager_infos) - - pdos_index = [] - exclusive_pdos = {} - selected_pdos = [] - for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] + - [(pdo, "Outputs") for pdo in device.getRxPdo()]): - - pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) - pdos_index.append(pdo_index) - - excluded_list = pdo.getExclude() - if len(excluded_list) > 0: - exclusion_list = [pdo_index] - for excluded in excluded_list: - exclusion_list.append(ExtractHexDecValue(excluded.getcontent())) - exclusion_list.sort() - - exclusion_scope = exclusive_pdos.setdefault(tuple(exclusion_list), []) - - entries = pdo.getEntry() - pdo_mapping_match = { - "index": pdo_index, - "matching": 0, - "count": len(entries), - "assigned": pdo.getSm() is not None - } - exclusion_scope.append(pdo_mapping_match) - - for entry in entries: - index = ExtractHexDecValue(entry.getIndex().getcontent()) - subindex = ExtractHexDecValue(entry.getSubIndex()) - if slave_variables.get((index, subindex), None) is not None: - pdo_mapping_match["matching"] += 1 - - elif pdo.getMandatory(): - selected_pdos.append(pdo_index) - - excluded_pdos = [] - for exclusion_scope in exclusive_pdos.itervalues(): - exclusion_scope.sort(ExclusionSortFunction) - start_excluding_index = 0 - if exclusion_scope[0]["matching"] > 0: - selected_pdos.append(exclusion_scope[0]["index"]) - start_excluding_index = 1 - excluded_pdos.extend([pdo["index"] for pdo in exclusion_scope[start_excluding_index:] if PdoAssign or not pdo["assigned"]]) - - for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] + - [(pdo, "Outputs") for pdo in device.getRxPdo()]): - entries = pdo.getEntry() - - pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent()) - if pdo_index in excluded_pdos: - continue - - pdo_needed = pdo_index in selected_pdos - - entries_infos = [] - - for entry in entries: - index = ExtractHexDecValue(entry.getIndex().getcontent()) - subindex = ExtractHexDecValue(entry.getSubIndex()) - entry_infos = { - "index": index, - "subindex": subindex, - "name": ExtractName(entry.getName()), - "bitlen": entry.getBitLen(), - } - entry_infos.update(type_infos) - entries_infos.append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos) - - entry_declaration = slave_variables.get((index, subindex), None) - if entry_declaration is not None and not entry_declaration["mapped"]: - pdo_needed = True - - entry_infos.update(dict(zip(["var_type", "dir", "var_name", "no_decl", "extra_declarations"], - entry_declaration["infos"]))) - entry_declaration["mapped"] = True - - entry_type = entry.getDataType().getcontent() - if entry_infos["var_type"] != entry_type: - message = _("Wrong type for location \"%s\"!") % entry_infos["var_name"] - if (self.Controler.GetSizeOfType(entry_infos["var_type"]) != - self.Controler.GetSizeOfType(entry_type)): - raise ValueError, message - else: - self.Controler.GetCTRoot().logger.write_warning(_("Warning: ") + message + "\n") - - if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or - entry_infos["dir"] == "Q" and pdo_type != "Outputs"): - raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"] - - ConfigureVariable(entry_infos, str_completion) - - elif pdo_type == "Outputs" and entry.getDataType() is not None and device_coe is not None: - data_type = entry.getDataType().getcontent() - entry_infos["dir"] = "Q" - entry_infos["data_size"] = max(1, entry_infos["bitlen"] / 8) - entry_infos["data_type"] = DATATYPECONVERSION.get(data_type) - entry_infos["var_type"] = data_type - entry_infos["real_var"] = "slave%(slave)d_%(index).4x_%(subindex).2x_default" % entry_infos - - ConfigureVariable(entry_infos, str_completion) - - str_completion["slaves_output_pdos_default_values_extraction"] += \ - SLAVE_OUTPUT_PDO_DEFAULT_VALUE % entry_infos - - if pdo_needed: - for excluded in pdo.getExclude(): - excluded_index = ExtractHexDecValue(excluded.getcontent()) - if excluded_index not in excluded_pdos: - excluded_pdos.append(excluded_index) - - sm = pdo.getSm() - if sm is None: - for sm_idx, sync_manager in enumerate(sync_managers): - if sync_manager["name"] == pdo_type: - sm = sm_idx - if sm is None: - raise ValueError, _("No sync manager available for %s pdo!") % pdo_type - - sync_managers[sm]["pdos_number"] += 1 - sync_managers[sm]["pdos"].append( - {"slave": slave_idx, - "index": pdo_index, - "name": ExtractName(pdo.getName()), - "type": pdo_type, - "entries": entries_infos, - "entries_number": len(entries_infos), - "fixed": pdo.getFixed() == True}) - - if PdoConfig and PdoAssign: - dynamic_pdos = {} - dynamic_pdos_number = 0 - for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), - ("Outputs", 0x1a00, 0x1C00)]: - for sync_manager in sync_managers: - if sync_manager["name"] == category: - category_infos = dynamic_pdos.setdefault(category, {}) - category_infos["sync_manager"] = sync_manager - category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"] - if not pdo["fixed"] and pdo["type"] == category] - category_infos["current_index"] = min_index - category_infos["max_index"] = max_index - break - - for (index, subindex), entry_declaration in slave_variables.iteritems(): - - if not entry_declaration["mapped"]: - entry = device_entries.get((index, subindex), None) - if entry is None: - raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \ - (index, subindex, type_infos["device_type"]) - - entry_infos = { - "index": index, - "subindex": subindex, - "name": entry["Name"], - "bitlen": entry["BitSize"], - } - entry_infos.update(type_infos) - - entry_infos.update(dict(zip(["var_type", "dir", "var_name", "no_decl", "extra_declarations"], - entry_declaration["infos"]))) - entry_declaration["mapped"] = True - - if entry_infos["var_type"] != entry["Type"]: - message = _("Wrong type for location \"%s\"!") % entry_infos["var_name"] - if (self.Controler.GetSizeOfType(entry_infos["var_type"]) != - self.Controler.GetSizeOfType(entry["Type"])): - raise ValueError, message - else: - self.Controler.GetCTRoot().logger.write_warning(message + "\n") - - if entry_infos["dir"] == "I" and entry["PDOMapping"] in ["T", "RT"]: - pdo_type = "Inputs" - elif entry_infos["dir"] == "Q" and entry["PDOMapping"] in ["R", "RT"]: - pdo_type = "Outputs" - else: - raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"] - - if not dynamic_pdos.has_key(pdo_type): - raise ValueError, _("No Sync manager defined for %s!") % pdo_type - - ConfigureVariable(entry_infos, str_completion) - - if len(dynamic_pdos[pdo_type]["pdos"]) > 0: - pdo = dynamic_pdos[pdo_type]["pdos"][0] - else: - while dynamic_pdos[pdo_type]["current_index"] in pdos_index: - dynamic_pdos[pdo_type]["current_index"] += 1 - if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]: - raise ValueError, _("No more free PDO index available for %s!") % pdo_type - pdos_index.append(dynamic_pdos[pdo_type]["current_index"]) - - dynamic_pdos_number += 1 - pdo = {"slave": slave_idx, - "index": dynamic_pdos[pdo_type]["current_index"], - "name": "Dynamic PDO %d" % dynamic_pdos_number, - "type": pdo_type, - "entries": [], - "entries_number": 0, - "fixed": False} - dynamic_pdos[pdo_type]["sync_manager"]["pdos_number"] += 1 - dynamic_pdos[pdo_type]["sync_manager"]["pdos"].append(pdo) - dynamic_pdos[pdo_type]["pdos"].append(pdo) - - pdo["entries"].append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos) - if entry_infos["bitlen"] < alignment: - print (alignment, entry_infos["bitlen"]) - pdo["entries"].append(" {0x0000, 0x00, %d}, /* None */" % (alignment - entry_infos["bitlen"])) - pdo["entries_number"] += 1 - - if pdo["entries_number"] == 255: - dynamic_pdos[pdo_type]["pdos"].pop(0) - - pdo_offset = 0 - entry_offset = 0 - for sync_manager_infos in sync_managers: - - for pdo_infos in sync_manager_infos["pdos"]: - pdo_infos["offset"] = entry_offset - pdo_entries = pdo_infos["entries"] - pdos_infos["pdos_infos"].append( - (" {0x%(index).4x, %(entries_number)d, " + - "slave_%(slave)d_pdo_entries + %(offset)d}, /* %(name)s */") % pdo_infos) - entry_offset += len(pdo_entries) - pdos_infos["pdos_entries_infos"].extend(pdo_entries) - - sync_manager_infos["offset"] = pdo_offset - pdo_offset_shift = sync_manager_infos["pdos_number"] - pdos_infos["pdos_sync_infos"].append( - (" {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " + - ("slave_%(slave)d_pdos + %(offset)d" if pdo_offset_shift else "NULL") + - ", %(watchdog)s},") % sync_manager_infos) - pdo_offset += pdo_offset_shift - - for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]: - pdos_infos[element] = "\n".join(pdos_infos[element]) - - str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos - - for (index, subindex), entry_declaration in slave_variables.iteritems(): - if not entry_declaration["mapped"]: - message = _("Entry index 0x%4.4x, subindex 0x%2.2x not mapped for device %s") % \ - (index, subindex, type_infos["device_type"]) - self.Controler.GetCTRoot().logger.write_warning(_("Warning: ") + message + "\n") - - for element in ["used_pdo_entry_offset_variables_declaration", - "used_pdo_entry_configuration", - "located_variables_declaration", - "retrieve_variables", - "publish_variables"]: - str_completion[element] = "\n".join(str_completion[element]) - - etherlabfile = open(filepath, 'w') - etherlabfile.write(plc_etherlab_code % str_completion) - etherlabfile.close() + +from EthercatSlave import ExtractHexDecValue, ExtractName +from EthercatMaster import _EthercatCTN +from ConfigEditor import LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE #-------------------------------------------------- # Ethercat ConfNode @@ -1860,15 +200,6 @@ SortGroupItems(item) group["children"].sort(GroupItemCompare) -def ExtractName(names, default=None): - if len(names) == 1: - return names[0].getcontent() - else: - for name in names: - if name.getLcId() == 1033: - return name.getcontent() - return default - def ExtractPdoInfos(pdo, pdo_type, entries, limits=None): pdo_index = pdo.getIndex().getcontent() pdo_name = ExtractName(pdo.getName())