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