--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EthercatCFileGenerator.py Fri Mar 29 01:15:01 2013 +0100
@@ -0,0 +1,547 @@
+from EthercatSlave import ExtractHexDecValue, DATATYPECONVERSION, ExtractName +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[] = { +ec_pdo_info_t slave_%(slave)d_pdos[] = { +ec_sync_info_t slave_%(slave)d_syncs[] = { +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"); + 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"); +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); +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); + %(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) + 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) + 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"]: + elif not x["assigned"] and y["assigned"]: + return cmp(x["count"], y["count"]) + return -cmp(x["matching"], y["matching"]) +class _EthercatCFileGenerator: + def __init__(self, controler): + self.Controler = controler + self.UsedVariables = {} + 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, []), + elif entry_infos["infos"][:2] == (iec_type, dir): + if name != entry_infos["infos"][2]: + entry_infos["infos"][4].append(name) + return entry_infos["infos"][2] + raise ValueError, _("Output variables can't be defined with different locations (%s and %s)") % (entry_infos["infos"][2], name) + 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 + "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) + # Initialize dictionary storing alias auto-increment position values + # 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 + slave_pos = (slave_alias, alias[slave_alias]) + # Extract slave device informations + device, alignment = self.Controler.GetModuleInfos(type_infos) + # 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 + for initCmd in device_coe.getInitCmd(): + "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) + data_size = entry["BitSize"] / 8 + data_str = ("0x%%.%dx" % (data_size * 2)) % initCmd["Value"] + "data_type": DATATYPECONVERSION.get(entry["Type"]), + 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() + 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 + "pdos_entries_infos": [], + pdos_infos.update(type_infos) + for sync_manager_idx, sync_manager in enumerate(device.getSm()): + "index": sync_manager_idx, + "name": sync_manager.getcontent(), + 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" + sync_manager_infos["sync_manager_type"] = "EC_DIR_INPUT" + if sync_manager_watchdog: + sync_manager_infos["watchdog"] = "EC_WD_ENABLE" + sync_manager_infos["watchdog"] = "EC_WD_DISABLE" + sync_managers.append(sync_manager_infos) + 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_scope = exclusive_pdos.setdefault(tuple(exclusion_list), []) + entries = pdo.getEntry() + "assigned": pdo.getSm() is not None + exclusion_scope.append(pdo_mapping_match) + 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) + 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: + pdo_needed = pdo_index in selected_pdos + index = ExtractHexDecValue(entry.getIndex().getcontent()) + subindex = ExtractHexDecValue(entry.getSubIndex()) + "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"]: + 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 + 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 + for excluded in pdo.getExclude(): + excluded_index = ExtractHexDecValue(excluded.getcontent()) + if excluded_index not in excluded_pdos: + excluded_pdos.append(excluded_index) + for sm_idx, sync_manager in enumerate(sync_managers): + if sync_manager["name"] == pdo_type: + raise ValueError, _("No sync manager available for %s pdo!") % pdo_type + sync_managers[sm]["pdos_number"] += 1 + sync_managers[sm]["pdos"].append( + "name": ExtractName(pdo.getName()), + "entries": entries_infos, + "entries_number": len(entries_infos), + "fixed": pdo.getFixed() == True}) + if PdoConfig and PdoAssign: + 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 + for (index, subindex), entry_declaration in slave_variables.iteritems(): + if not entry_declaration["mapped"]: + entry = device_entries.get((index, subindex), None) + raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \ + (index, subindex, type_infos["device_type"]) + "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 + self.Controler.GetCTRoot().logger.write_warning(message + "\n") + if entry_infos["dir"] == "I" and entry["PDOMapping"] in ["T", "RT"]: + elif entry_infos["dir"] == "Q" and entry["PDOMapping"] in ["R", "RT"]: + 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] + 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, + 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) + 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", + str_completion[element] = "\n".join(str_completion[element]) + etherlabfile = open(filepath, 'w') + etherlabfile.write(plc_etherlab_code % str_completion) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EthercatCIA402Slave.py Fri Mar 29 01:15:01 2013 +0100
@@ -0,0 +1,258 @@
+from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY +from MotionLibrary import Headers, AxisXSD +from EthercatSlave import _EthercatSlaveCTN +from ConfigEditor import CIA402NodeEditor + ("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 = [ + {"description": ("ErrorCode", 0x603F, 0x00, "UINT", "I"), + {"description": ("DigitalInputs", 0x60FD, 0x00, "UDINT", "I"), + {"description": ("DigitalOutputs", 0x60FE, 0x00, "UDINT", "Q"), +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(); +ETHERLAB%(ucase_blocktype)s_body__(%(blockname)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;""" + {"blocktype": "GetTorqueLimit", + "outputs": [{"name": "TorqueLimitPos", "type": "UINT"}, + {"name": "TorqueLimitNeg", "type": "UINT"}]}, + {"blocktype": "SetTorqueLimit", + "inputs": [{"name": "TorqueLimitPos", "type": "UINT"}, + {"name": "TorqueLimitNeg", "type": "UINT"}], +#-------------------------------------------------- +#-------------------------------------------------- +class _EthercatCIA402SlaveCTN(_EthercatSlaveCTN): + XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:element name="CIA402SlaveParams"> + """ % ("\n".join(['<xsd:attribute name="Enable%s" type="xsd:boolean" use="optional" default="false"/>' % category + for category, variables in EXTRA_NODE_VARIABLES]) + AxisXSD) + EditorType = CIA402NodeEditor + {"bitmap" : "CIA402AxisRef", + "name" : _("Axis Ref"), + "tooltip" : _("Initiate Drag'n drop of Axis ref located variable"), + "method" : "_getCIA402AxisRef", + 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, + "IEC_type": "AXIS_REF", + "location": "%%IW%s.0" % (".".join(map(str, current_location))), + children.extend(self.CTNParent.GetDeviceLocationTree(self.GetSlavePos(), current_location, axis_name)) + return {"name": axis_name, + "type": LOCATION_CONFNODE, + "location": self.GetFullIEC_Channel(), + 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() + "slave_pos": self.GetSlavePos(), + "location": location_str, + "MCL_headers": Headers, + "extern_located_variables_declaration": [], + "fieldbus_interface_declaration": [], + "fieldbus_interface_definition": [], + "init_axis_params": [], + "init_entry_variables": [], + "extra_variables_retrieve": [], + "extra_variables_publish": [] + for blocktype_infos in GLOBAL_INSTANCES: + "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"]] + 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"]] + 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: + extra_variables = EXTRA_NODE_VARIABLES_DICT.get(param["name"]) + for variable_infos in extra_variables: + "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: + "location": location_str, + "param_name": param["name"], + if param["type"] == "boolean": + param_infos["param_value"] = {True: "true", False: "false"}[param["value"]] + 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", + "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) + return [(Gen_CIA402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))],"",True --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EthercatMaster.py Fri Mar 29 01:15:01 2013 +0100
@@ -0,0 +1,762 @@
+from xml.dom import minidom +from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY +from ConfigTreeNode import ConfigTreeNode +from dialogs import BrowseValuesLibraryDialog +from IDEFrame import TITLE, FILEMENU, PROJECTTREE +from EthercatSlave import _EthercatSlaveCTN, ExtractHexDecValue, GenerateHexDecValue, TYPECONVERSION, VARCLASSCONVERSION +from EthercatCFileGenerator import _EthercatCFileGenerator +from ConfigEditor import MasterEditor +from POULibrary import POULibrary + from EthercatCIA402Slave import _EthercatCIA402SlaveCTN +#-------------------------------------------------- +# Remote Exec Etherlab Commands +#-------------------------------------------------- +result = commands.getoutput("ethercat 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), + "position": int(position), + 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] +#-------------------------------------------------- +# 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) + 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")))) +#-------------------------------------------------- +#-------------------------------------------------- +EtherCATConfigClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATConfig.xsd")) +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) + 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() + Mailbox = self.getMailbox() + InitCmds = CoE.getInitCmds() + if InitCmds is None and create_default: + InitCmds = CoE.getInitCmds() + setattr(cls, "getInitCmds", getInitCmds) + def getStartupCommands(self): + pos = self.getInfo().getPhysAddr() + InitCmds = self.getInitCmds() + for idx, InitCmd in enumerate(InitCmds.getInitCmd()): + comment = InitCmd.getComment() + "Index": InitCmd.getIndex(), + "Subindex": InitCmd.getSubIndex(), + "Value": InitCmd.getData(), + "Description": comment}) + commands.sort(sort_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 = """<?xml version="1.0" encoding="ISO-8859-1" ?> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:element name="ProcessVariables"> + <xsd:element name="variable" minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="ReadFrom" type="LocationDesc" minOccurs="0"/> + <xsd:element name="WriteTo" type="LocationDesc" minOccurs="0"/> + <xsd:attribute name="Name" type="xsd:string" use="required"/> + <xsd:attribute name="Comment" type="xsd:string" use="required"/> + <xsd:complexType name="LocationDesc"> + <xsd:attribute name="Position" type="xsd:integer" use="required"/> + <xsd:attribute name="Index" type="xsd:integer" use="required"/> + <xsd:attribute name="SubIndex" type="xsd:integer" use="required"/> +ProcessVariablesClasses = GenerateClassesFromXSDstring(ProcessVariablesXSD) + CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")] + CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave")) + EditorType = MasterEditor + 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) + for child in config_tree.childNodes: + if child.nodeType == config_tree.ELEMENT_NODE and child.nodeName == "EtherCATConfig": + self.Config.loadXMLTree(child) + 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) + self.CreateBuffer(False) + 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 HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): + ConfNodeType = "EthercatCIA402Slave" + ConfNodeType = "EthercatSlave" + new_child = self.CTNAddChild("%s_0" % ConfNodeType, ConfNodeType) + new_child.SetParamsAttribute("SlaveParams.Type", type_infos) + app_frame._Refresh(TITLE, FILEMENU, PROJECTTREE) + 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: + type_infos = slave.getType() + if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: + device, alignment = self.GetModuleInfos(type_infos) + if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): + def GetSlaves(self, vendor=None, slave_pos=None, slave_profile=None): + for slave in self.Config.getConfig().getSlave(): + if self.FilterSlave(slave, vendor, slave_pos, slave_profile): + slaves.append(slave.getInfo().getPhysAddr()) + def GetSlave(self, slave_pos): + for slave in self.Config.getConfig().getSlave(): + slave_info = slave.getInfo() + if slave_info.getPhysAddr() == slave_pos: + def GetStartupCommands(self, vendor=None, slave_pos=None, slave_profile=None): + for slave in self.Config.getConfig().getSlave(): + if self.FilterSlave(slave, vendor, slave_pos, slave_profile): + commands.append((slave.getInfo().getPhysAddr(), slave.getStartupCommands())) + return reduce(lambda x, y: x + y[1], commands, []) + def AppendStartupCommand(self, command_infos): + slave = self.GetSlave(command_infos["Position"]) + command_idx = slave.appendStartupCommand(command_infos) + def SetStartupCommandInfos(self, command_infos): + slave = self.GetSlave(command_infos["Position"]) + slave.setStartupCommand(command_infos) + def RemoveStartupCommand(self, slave_pos, command_idx, buffer=True): + slave = self.GetSlave(slave_pos) + slave.removeStartupCommand(command_idx) + def SetProcessVariables(self, 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: + 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: + write_to = variable.getWriteTo() + write_to.setPosition(position) + write_to.setIndex(index) + write_to.setSubIndex(subindex) + elif variable.getWriteTo() is not None: + variable.deleteWriteTo() + self.ProcessVariables.setvariable(vars) + def GetProcessVariables(self): + for variable in self.ProcessVariables.getvariable(): + var = {"Name": variable.getName(), + "Description": variable.getComment()} + read_from = variable.getReadFrom() + if read_from is not None: + var["ReadFrom"] = (read_from.getPosition(), + read_from.getSubIndex()) + write_to = variable.getWriteTo() + if write_to is not None: + var["WriteTo"] = (write_to.getPosition(), + write_to.getSubIndex()) + def _ScanNetwork(self): + app_frame = self.GetCTRoot().AppFrame + if len(self.Children) > 0: + dialog = wx.MessageDialog(app_frame, + _("The current network configuration will be deleted.\nDo you want to continue?"), + wx.YES_NO|wx.ICON_QUESTION) + execute = dialog.ShowModal() == wx.ID_YES + error, returnVal = self.RemoteExec(SCAN_COMMAND, returnVal = None) + dialog = wx.MessageDialog(app_frame, returnVal, "Error", wx.OK|wx.ICON_ERROR) + elif returnVal is not None: + for child in self.IECSortedChildren(): + self._doRemoveChild(child) + for slave in returnVal: + "vendor": slave["vendor_id"], + "product_code": slave["product_code"], + "revision_number":slave["revision_number"], + device, alignment = self.GetModuleInfos(type_infos) + if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): + CTNType = "EthercatCIA402Slave" + 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()) + 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) + 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) + ConfigTreeNode._doRemoveChild(self, CTNInstance) + def SetSlavePosition(self, slave_pos, new_pos): + slave = self.GetSlave(slave_pos) + 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) + if self._View is not None: + self._View.RefreshView() + self._View.RefreshBuffer() + def GetSlaveAlias(self, slave_pos): + slave = self.GetSlave(slave_pos) + slave_info = slave.getInfo() + return slave_info.getAutoIncAddr() + def SetSlaveAlias(self, slave_pos, alias): + slave = self.GetSlave(slave_pos) + slave_info = slave.getInfo() + slave_info.setAutoIncAddr(alias) + def GetSlaveType(self, slave_pos): + slave = self.GetSlave(slave_pos) + def SetSlaveType(self, slave_pos, type_infos): + slave = self.GetSlave(slave_pos) + slave.setType(type_infos) + def GetSlaveInfos(self, slave_pos): + slave = self.GetSlave(slave_pos) + type_infos = slave.getType() + device, alignment = self.GetModuleInfos(type_infos) + infos = type_infos.copy() + infos.update({"physics": device.getPhysics(), + "sync_managers": device.GetSyncManagers(), + "entries": self.GetSlaveVariables(device)}) + 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) + type_infos = slave.getType() + device, alignment = self.GetModuleInfos(type_infos) + entries = device.GetEntriesList(limits) + entries_list = entries.items() + for (index, subindex), entry in entries_list: + if slave_pos is not None: + entry["Position"] = str(slave_pos) + if index != current_index: + elif current_entry is not None: + current_entry["children"].append(entry) + def GetSlaveVariableDataType(self, slave_pos, index, subindex): + slave = self.GetSlave(slave_pos) + device, alignment = self.GetModuleInfos(slave.getType()) + entries = device.GetEntriesList() + entry_infos = entries.get((index, subindex)) + if entry_infos is not None: + return entry_infos["Type"] + def GetNodesVariables(self, vendor=None, slave_pos=None, slave_profile=None, limits=None): + for slave_position in self.GetSlaves(): + if slave_pos is not None and slave_position != slave_pos: + slave = self.GetSlave(slave_position) + type_infos = slave.getType() + if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: + device, alignment = self.GetModuleInfos(type_infos) + if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): + entries.extend(self.GetSlaveVariables(slave_position, limits, device)) + 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) + type_infos = slave.getType() + device, alignment = self.GetModuleInfos(type_infos) + 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) + sync_managers.append(LOCATION_VAR_INPUT) + entries = device.GetEntriesList().items() + 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: + vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]), + "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 + + def CTNTestModified(self): + return self.ChangesToSave or not self.ModelIsSaved() + config_filepath = self.ConfigFileName() + config_text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\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")) + process_filepath = self.ProcessVariablesFileName() + process_text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\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() + 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()): + 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() + 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( + [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))], + LDFLAGS.append("-lethercat -lrtdm") + return LocationCFilesAndCFLAGS, LDFLAGS, extra_files + {"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) + self.FileGenerator.DeclareSlave(slave_pos, slave) + for location in locations: + loc = location["LOC"][len(current_location):] + 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"]) +#------------------------------------------------------------------------------- +# Current Buffering Management Functions +#------------------------------------------------------------------------------- + Return a copy of the config + return cPickle.loads(cPickle.dumps(model)) + def CreateBuffer(self, saved): + self.Buffer = UndoBuffer(cPickle.dumps((self.Config, self.ProcessVariables)), saved) + self.Buffer.Buffering(cPickle.dumps((self.Config, self.ProcessVariables))) + def ModelIsSaved(self): + if self.Buffer is not None: + return self.Buffer.IsCurrentSaved() + def LoadPrevious(self): + self.Config, self.ProcessVariables = cPickle.loads(self.Buffer.Previous()) + 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 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/etherlab/EthercatSlave.py Fri Mar 29 01:15:01 2013 +0100
@@ -0,0 +1,135 @@
+from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY +from ConfigTreeNode import ConfigTreeNode +from ConfigEditor import NodeEditor +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} +def ExtractHexDecValue(value): + return int(value.replace("#", "0"), 16) + raise ValueError, "Invalid value for HexDecValue \"%s\"" % value +def GenerateHexDecValue(value, base=10): + return "#x%.8x" % value + raise ValueError, "Not supported base" +def ExtractName(names, default=None): + return names[0].getcontent() + if name.getLcId() == 1033: + return name.getcontent() +#-------------------------------------------------- +#-------------------------------------------------- +class _EthercatSlaveCTN: + EditorType = NodeEditor + def ExtractHexDecValue(self, value): + return ExtractHexDecValue(value) + def GetSizeOfType(self, type): + return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None) + return self.BaseParams.getIEC_Channel() + def GetParamsAttributes(self, path = None): + 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]) + params.append(self.CTNParams[1].getElementInfos(self.CTNParams[0])) + slave_type = self.CTNParent.GetSlaveType(self.GetSlavePos()) + params[0]['children'].insert(0, + 'type': self.CTNParent.GetSlaveTypesLibrary(self.NODE_PROFILE), + 'value': (slave_type["device_type"], slave_type)}) + params[0]['children'].insert(1, + 'type': 'unsignedLong', + 'value': self.CTNParent.GetSlaveAlias(self.GetSlavePos())}) + 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) + elif path == "SlaveParams.Alias": + self.CTNParent.SetSlaveAlias(position, value) + 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) + 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): --- 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 @@
from xml.dom import minidom
-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
- from MotionLibrary import Headers, AxisXSD
-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
-#--------------------------------------------------
-result = commands.getoutput("ethercat 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),
- "position": int(position),
- 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]
-#--------------------------------------------------
-# 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)
- 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"))))
-#--------------------------------------------------
-#--------------------------------------------------
-class _EthercatSlaveCTN:
- EditorType = NodeEditor
- def ExtractHexDecValue(self, value):
- return ExtractHexDecValue(value)
- def GetSizeOfType(self, type):
- return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None)
- return self.BaseParams.getIEC_Channel()
- def GetParamsAttributes(self, path = None):
- 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])
- params.append(self.CTNParams[1].getElementInfos(self.CTNParams[0]))
- slave_type = self.CTNParent.GetSlaveType(self.GetSlavePos())
- params[0]['children'].insert(0,
- 'type': self.CTNParent.GetSlaveTypesLibrary(self.NODE_PROFILE),
- 'value': (slave_type["device_type"], slave_type)})
- params[0]['children'].insert(1,
- 'type': 'unsignedLong',
- 'value': self.CTNParent.GetSlaveAlias(self.GetSlavePos())})
- 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)
- elif path == "SlaveParams.Alias":
- self.CTNParent.SetSlaveAlias(position, value)
- 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)
- 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):
-#--------------------------------------------------
-#--------------------------------------------------
- ("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 = [
- {"description": ("ErrorCode", 0x603F, 0x00, "UINT", "I"),
- {"description": ("DigitalInputs", 0x60FD, 0x00, "UDINT", "I"),
- {"description": ("DigitalOutputs", 0x60FE, 0x00, "UDINT", "Q"),
- 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();
- ETHERLAB%(ucase_blocktype)s_body__(%(blockname)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;"""
- {"blocktype": "GetTorqueLimit",
- "outputs": [{"name": "TorqueLimitPos", "type": "UINT"},
- {"name": "TorqueLimitNeg", "type": "UINT"}]},
- {"blocktype": "SetTorqueLimit",
- "inputs": [{"name": "TorqueLimitPos", "type": "UINT"},
- {"name": "TorqueLimitNeg", "type": "UINT"}],
- class _EthercatCIA402SlaveCTN(_EthercatSlaveCTN):
- XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="CIA402SlaveParams">
- """ % ("\n".join(['<xsd:attribute name="Enable%s" type="xsd:boolean" use="optional" default="false"/>' % category
- for category, variables in EXTRA_NODE_VARIABLES]) + AxisXSD)
- EditorType = CIA402NodeEditor
- {"bitmap" : "CIA402AxisRef",
- "name" : _("Axis Ref"),
- "tooltip" : _("Initiate Drag'n drop of Axis ref located variable"),
- "method" : "_getCIA402AxisRef",
- 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,
- "IEC_type": "AXIS_REF",
- "location": "%%IW%s.0" % (".".join(map(str, current_location))),
- children.extend(self.CTNParent.GetDeviceLocationTree(self.GetSlavePos(), current_location, axis_name))
- return {"name": axis_name,
- "type": LOCATION_CONFNODE,
- "location": self.GetFullIEC_Channel(),
- 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()
- "slave_pos": self.GetSlavePos(),
- "location": location_str,
- "MCL_headers": Headers,
- "extern_located_variables_declaration": [],
- "fieldbus_interface_declaration": [],
- "fieldbus_interface_definition": [],
- "init_axis_params": [],
- "init_entry_variables": [],
- "extra_variables_retrieve": [],
- "extra_variables_publish": []
- for blocktype_infos in GLOBAL_INSTANCES:
- "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"]]
- 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"]]
- 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:
- extra_variables = EXTRA_NODE_VARIABLES_DICT.get(param["name"])
- for variable_infos in extra_variables:
- "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:
- "location": location_str,
- "param_name": param["name"],
- if param["type"] == "boolean":
- param_infos["param_value"] = {True: "true", False: "false"}[param["value"]]
- 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",
- "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)
- return [(Gen_CIA402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))],"",True
-#--------------------------------------------------
-#--------------------------------------------------
-EtherCATConfigClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATConfig.xsd"))
-def ExtractHexDecValue(value):
- return int(value.replace("#", "0"), 16)
- raise ValueError, "Invalid value for HexDecValue \"%s\"" % value
-def GenerateHexDecValue(value, base=10):
- return "#x%.8x" % value
- 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)
- 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()
- Mailbox = self.getMailbox()
- InitCmds = CoE.getInitCmds()
- if InitCmds is None and create_default:
- InitCmds = CoE.getInitCmds()
- setattr(cls, "getInitCmds", getInitCmds)
- def getStartupCommands(self):
- pos = self.getInfo().getPhysAddr()
- InitCmds = self.getInitCmds()
- for idx, InitCmd in enumerate(InitCmds.getInitCmd()):
- comment = InitCmd.getComment()
- "Index": InitCmd.getIndex(),
- "Subindex": InitCmd.getSubIndex(),
- "Value": InitCmd.getData(),
- "Description": comment})
- commands.sort(sort_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 = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="ProcessVariables">
- <xsd:element name="variable" minOccurs="0" maxOccurs="unbounded">
- <xsd:element name="ReadFrom" type="LocationDesc" minOccurs="0"/>
- <xsd:element name="WriteTo" type="LocationDesc" minOccurs="0"/>
- <xsd:attribute name="Name" type="xsd:string" use="required"/>
- <xsd:attribute name="Comment" type="xsd:string" use="required"/>
- <xsd:complexType name="LocationDesc">
- <xsd:attribute name="Position" type="xsd:integer" use="required"/>
- <xsd:attribute name="Index" type="xsd:integer" use="required"/>
- <xsd:attribute name="SubIndex" type="xsd:integer" use="required"/>
-ProcessVariablesClasses = GenerateClassesFromXSDstring(ProcessVariablesXSD)
- CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")]
- CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave"))
- EditorType = MasterEditor
- 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)
- for child in config_tree.childNodes:
- if child.nodeType == config_tree.ELEMENT_NODE and child.nodeName == "EtherCATConfig":
- self.Config.loadXMLTree(child)
- 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)
- self.CreateBuffer(False)
- 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 HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers():
- ConfNodeType = "EthercatCIA402Slave"
- ConfNodeType = "EthercatSlave"
- new_child = self.CTNAddChild("%s_0" % ConfNodeType, ConfNodeType)
- new_child.SetParamsAttribute("SlaveParams.Type", type_infos)
- app_frame._Refresh(TITLE, FILEMENU, PROJECTTREE)
- 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:
- type_infos = slave.getType()
- if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor:
- device, alignment = self.GetModuleInfos(type_infos)
- if slave_profile is not None and slave_profile not in device.GetProfileNumbers():
- def GetSlaves(self, vendor=None, slave_pos=None, slave_profile=None):
- for slave in self.Config.getConfig().getSlave():
- if self.FilterSlave(slave, vendor, slave_pos, slave_profile):
- slaves.append(slave.getInfo().getPhysAddr())
- def GetSlave(self, slave_pos):
- for slave in self.Config.getConfig().getSlave():
- slave_info = slave.getInfo()
- if slave_info.getPhysAddr() == slave_pos:
- def GetStartupCommands(self, vendor=None, slave_pos=None, slave_profile=None):
- for slave in self.Config.getConfig().getSlave():
- if self.FilterSlave(slave, vendor, slave_pos, slave_profile):
- commands.append((slave.getInfo().getPhysAddr(), slave.getStartupCommands()))
- return reduce(lambda x, y: x + y[1], commands, [])
- def AppendStartupCommand(self, command_infos):
- slave = self.GetSlave(command_infos["Position"])
- command_idx = slave.appendStartupCommand(command_infos)
- def SetStartupCommandInfos(self, command_infos):
- slave = self.GetSlave(command_infos["Position"])
- slave.setStartupCommand(command_infos)
- def RemoveStartupCommand(self, slave_pos, command_idx, buffer=True):
- slave = self.GetSlave(slave_pos)
- slave.removeStartupCommand(command_idx)
- def SetProcessVariables(self, 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:
- 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:
- write_to = variable.getWriteTo()
- write_to.setPosition(position)
- write_to.setIndex(index)
- write_to.setSubIndex(subindex)
- elif variable.getWriteTo() is not None:
- variable.deleteWriteTo()
- self.ProcessVariables.setvariable(vars)
- def GetProcessVariables(self):
- for variable in self.ProcessVariables.getvariable():
- var = {"Name": variable.getName(),
- "Description": variable.getComment()}
- read_from = variable.getReadFrom()
- if read_from is not None:
- var["ReadFrom"] = (read_from.getPosition(),
- read_from.getSubIndex())
- write_to = variable.getWriteTo()
- if write_to is not None:
- var["WriteTo"] = (write_to.getPosition(),
- write_to.getSubIndex())
- def _ScanNetwork(self):
- app_frame = self.GetCTRoot().AppFrame
- if len(self.Children) > 0:
- dialog = wx.MessageDialog(app_frame,
- _("The current network configuration will be deleted.\nDo you want to continue?"),
- wx.YES_NO|wx.ICON_QUESTION)
- execute = dialog.ShowModal() == wx.ID_YES
- error, returnVal = self.RemoteExec(SCAN_COMMAND, returnVal = None)
- dialog = wx.MessageDialog(app_frame, returnVal, "Error", wx.OK|wx.ICON_ERROR)
- elif returnVal is not None:
- for child in self.IECSortedChildren():
- self._doRemoveChild(child)
- for slave in returnVal:
- "vendor": slave["vendor_id"],
- "product_code": slave["product_code"],
- "revision_number":slave["revision_number"],
- device, alignment = self.GetModuleInfos(type_infos)
- if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers():
- CTNType = "EthercatCIA402Slave"
- 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())
- 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)
- 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)
- ConfigTreeNode._doRemoveChild(self, CTNInstance)
- def SetSlavePosition(self, slave_pos, new_pos):
- slave = self.GetSlave(slave_pos)
- 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)
- if self._View is not None:
- self._View.RefreshView()
- self._View.RefreshBuffer()
- def GetSlaveAlias(self, slave_pos):
- slave = self.GetSlave(slave_pos)
- slave_info = slave.getInfo()
- return slave_info.getAutoIncAddr()
- def SetSlaveAlias(self, slave_pos, alias):
- slave = self.GetSlave(slave_pos)
- slave_info = slave.getInfo()
- slave_info.setAutoIncAddr(alias)
- def GetSlaveType(self, slave_pos):
- slave = self.GetSlave(slave_pos)
- def SetSlaveType(self, slave_pos, type_infos):
- slave = self.GetSlave(slave_pos)
- slave.setType(type_infos)
- def GetSlaveInfos(self, slave_pos):
- slave = self.GetSlave(slave_pos)
- type_infos = slave.getType()
- device, alignment = self.GetModuleInfos(type_infos)
- infos = type_infos.copy()
- infos.update({"physics": device.getPhysics(),
- "sync_managers": device.GetSyncManagers(),
- "entries": self.GetSlaveVariables(device)})
- 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)
- type_infos = slave.getType()
- device, alignment = self.GetModuleInfos(type_infos)
- entries = device.GetEntriesList(limits)
- entries_list = entries.items()
- for (index, subindex), entry in entries_list:
- if slave_pos is not None:
- entry["Position"] = str(slave_pos)
- if index != current_index:
- elif current_entry is not None:
- current_entry["children"].append(entry)
- def GetSlaveVariableDataType(self, slave_pos, index, subindex):
- slave = self.GetSlave(slave_pos)
- device, alignment = self.GetModuleInfos(slave.getType())
- entries = device.GetEntriesList()
- entry_infos = entries.get((index, subindex))
- if entry_infos is not None:
- return entry_infos["Type"]
- def GetNodesVariables(self, vendor=None, slave_pos=None, slave_profile=None, limits=None):
- for slave_position in self.GetSlaves():
- if slave_pos is not None and slave_position != slave_pos:
- slave = self.GetSlave(slave_position)
- type_infos = slave.getType()
- if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor:
- device, alignment = self.GetModuleInfos(type_infos)
- if slave_profile is not None and slave_profile not in device.GetProfileNumbers():
- entries.extend(self.GetSlaveVariables(slave_position, limits, device))
- 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)
- type_infos = slave.getType()
- device, alignment = self.GetModuleInfos(type_infos)
- 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)
- sync_managers.append(LOCATION_VAR_INPUT)
- entries = device.GetEntriesList().items()
- 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:
- vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]),
- "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 +
- def CTNTestModified(self):
- return self.ChangesToSave or not self.ModelIsSaved()
- config_filepath = self.ConfigFileName()
- config_text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\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"))
- process_filepath = self.ProcessVariablesFileName()
- process_text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\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()
- 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()):
- 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()
- 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(
- [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()))],
- LDFLAGS.append("-lethercat -lrtdm")
- return LocationCFilesAndCFLAGS, LDFLAGS, extra_files
- {"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)
- self.FileGenerator.DeclareSlave(slave_pos, slave)
- for location in locations:
- loc = location["LOC"][len(current_location):]
- 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"])
-#-------------------------------------------------------------------------------
-# Current Buffering Management Functions
-#-------------------------------------------------------------------------------
- Return a copy of the config
- return cPickle.loads(cPickle.dumps(model))
- def CreateBuffer(self, saved):
- self.Buffer = UndoBuffer(cPickle.dumps((self.Config, self.ProcessVariables)), saved)
- self.Buffer.Buffering(cPickle.dumps((self.Config, self.ProcessVariables)))
- def ModelIsSaved(self):
- if self.Buffer is not None:
- return self.Buffer.IsCurrentSaved()
- def LoadPrevious(self):
- self.Config, self.ProcessVariables = cPickle.loads(self.Buffer.Previous())
- 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[] = {
-ec_pdo_info_t slave_%(slave)d_pdos[] = {
-ec_sync_info_t slave_%(slave)d_syncs[] = {
-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");
- 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");
-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);
-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);
- %(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)
- 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)
- 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"]:
- elif not x["assigned"] and y["assigned"]:
- return cmp(x["count"], y["count"])
- return -cmp(x["matching"], y["matching"])
-class _EthercatCFileGenerator:
- def __init__(self, controler):
- self.Controler = controler
- self.UsedVariables = {}
- 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, []),
- elif entry_infos["infos"][:2] == (iec_type, dir):
- if name != entry_infos["infos"][2]:
- entry_infos["infos"][3].append(name)
- return entry_infos["infos"][2]
- raise ValueError, _("Output variables can't be defined with different locations (%s and %s)") % (entry_infos["infos"][2], name)
- 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
- "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)
- # Initialize dictionary storing alias auto-increment position values
- # 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
- slave_pos = (slave_alias, alias[slave_alias])
- # Extract slave device informations
- device, alignment = self.Controler.GetModuleInfos(type_infos)
- # 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
- for initCmd in device_coe.getInitCmd():
- "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)
- data_size = entry["BitSize"] / 8
- data_str = ("0x%%.%dx" % (data_size * 2)) % initCmd["Value"]
- "data_type": DATATYPECONVERSION.get(entry["Type"]),
- 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()
- 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
- "pdos_entries_infos": [],
- pdos_infos.update(type_infos)
- for sync_manager_idx, sync_manager in enumerate(device.getSm()):
- "index": sync_manager_idx,
- "name": sync_manager.getcontent(),
- 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"
- sync_manager_infos["sync_manager_type"] = "EC_DIR_INPUT"
- if sync_manager_watchdog:
- sync_manager_infos["watchdog"] = "EC_WD_ENABLE"
- sync_manager_infos["watchdog"] = "EC_WD_DISABLE"
- sync_managers.append(sync_manager_infos)
- 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_scope = exclusive_pdos.setdefault(tuple(exclusion_list), [])
- entries = pdo.getEntry()
- "assigned": pdo.getSm() is not None
- exclusion_scope.append(pdo_mapping_match)
- 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)
- 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:
- pdo_needed = pdo_index in selected_pdos
- index = ExtractHexDecValue(entry.getIndex().getcontent())
- subindex = ExtractHexDecValue(entry.getSubIndex())
- "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"]:
- 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
- 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
- for excluded in pdo.getExclude():
- excluded_index = ExtractHexDecValue(excluded.getcontent())
- if excluded_index not in excluded_pdos:
- excluded_pdos.append(excluded_index)
- for sm_idx, sync_manager in enumerate(sync_managers):
- if sync_manager["name"] == pdo_type:
- raise ValueError, _("No sync manager available for %s pdo!") % pdo_type
- sync_managers[sm]["pdos_number"] += 1
- sync_managers[sm]["pdos"].append(
- "name": ExtractName(pdo.getName()),
- "entries": entries_infos,
- "entries_number": len(entries_infos),
- "fixed": pdo.getFixed() == True})
- if PdoConfig and PdoAssign:
- 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
- for (index, subindex), entry_declaration in slave_variables.iteritems():
- if not entry_declaration["mapped"]:
- entry = device_entries.get((index, subindex), None)
- raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \
- (index, subindex, type_infos["device_type"])
- "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
- self.Controler.GetCTRoot().logger.write_warning(message + "\n")
- if entry_infos["dir"] == "I" and entry["PDOMapping"] in ["T", "RT"]:
- elif entry_infos["dir"] == "Q" and entry["PDOMapping"] in ["R", "RT"]:
- 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]
- 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,
- 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)
- 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",
- str_completion[element] = "\n".join(str_completion[element])
- etherlabfile = open(filepath, 'w')
- etherlabfile.write(plc_etherlab_code % str_completion)
+from EthercatSlave import ExtractHexDecValue, ExtractName +from EthercatMaster import _EthercatCTN +from ConfigEditor import LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE #--------------------------------------------------
@@ -1860,15 +200,6 @@
group["children"].sort(GroupItemCompare)
-def ExtractName(names, default=None):
- return names[0].getcontent()
- if name.getLcId() == 1033:
- return name.getcontent()
def ExtractPdoInfos(pdo, pdo_type, entries, limits=None):
pdo_index = pdo.getIndex().getcontent()
pdo_name = ExtractName(pdo.getName())
--- a/etherlab/extension.py Fri Mar 29 01:13:17 2013 +0100
+++ b/etherlab/extension.py Fri Mar 29 01:15:01 2013 +0100
@@ -1,7 +1,7 @@
def GetEtherLabLibClass():
- from etherlab import EtherlabLibrary
+ from EthercatMaster import EtherlabLibrary features.libraries.append(