edouard@2165: #!/usr/bin/env python edouard@2165: # -*- coding: utf-8 -*- edouard@2165: edouard@2165: # This file is part of Beremiz edouard@2165: # edouard@2165: # Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT edouard@2165: # RTES Lab : CRKim, JBLee, youcu edouard@2165: # Higen Motor : Donggu Kang edouard@2165: # edouard@2165: # See COPYING file for copyrights details. edouard@2165: Laurent@2111: import os andrej@2390: from copy import deepcopy Laurent@2157: from lxml import etree Laurent@2111: Laurent@2111: import wx Laurent@2111: Laurent@2111: from xmlclass import * Laurent@2111: andrej@2396: from PLCControler import UndoBuffer, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT Laurent@2111: from ConfigTreeNode import ConfigTreeNode Laurent@2111: from dialogs import BrowseValuesLibraryDialog Laurent@2111: from IDEFrame import TITLE, FILEMENU, PROJECTTREE andrej@2392: from POULibrary import POULibrary andrej@2392: andrej@2392: from ConfigEditor import MasterEditor andrej@2392: from EthercatCFileGenerator import _EthercatCFileGenerator Edouard@2152: from EthercatSlave import _EthercatSlaveCTN, ExtractHexDecValue, GenerateHexDecValue, TYPECONVERSION, VARCLASSCONVERSION, _CommonSlave Laurent@2111: Laurent@2111: try: Laurent@2111: from EthercatCIA402Slave import _EthercatCIA402SlaveCTN Laurent@2111: HAS_MCL = True andrej@2353: except Exception: Laurent@2111: HAS_MCL = False Laurent@2111: andrej@2356: # -------------------------------------------------- Laurent@2111: # Remote Exec Etherlab Commands andrej@2356: # -------------------------------------------------- Laurent@2111: Laurent@2111: SCAN_COMMAND = """ Laurent@2111: import commands Laurent@2111: result = commands.getoutput("ethercat slaves") Laurent@2111: slaves = [] Laurent@2111: for slave_line in result.splitlines(): Laurent@2111: chunks = slave_line.split() Laurent@2111: idx, pos, state, flag = chunks[:4] Laurent@2111: name = " ".join(chunks[4:]) Laurent@2111: alias, position = pos.split(":") Laurent@2111: slave = {"idx": int(idx), Laurent@2111: "alias": int(alias), Laurent@2111: "position": int(position), Laurent@2111: "name": name} Laurent@2111: details = commands.getoutput("ethercat slaves -p %d -v" % slave["idx"]) Laurent@2111: for details_line in details.splitlines(): Laurent@2111: details_line = details_line.strip() Laurent@2111: for header, param in [("Vendor Id:", "vendor_id"), Laurent@2111: ("Product code:", "product_code"), Laurent@2111: ("Revision number:", "revision_number")]: Laurent@2111: if details_line.startswith(header): Laurent@2111: slave[param] = details_line.split()[-1] Laurent@2111: break Laurent@2111: slaves.append(slave) Laurent@2111: returnVal = slaves Laurent@2111: """ Laurent@2111: andrej@2356: # -------------------------------------------------- Laurent@2111: # Etherlab Specific Blocks Library andrej@2356: # -------------------------------------------------- Laurent@2111: andrej@2360: Laurent@2111: def GetLocalPath(filename): Laurent@2111: return os.path.join(os.path.split(__file__)[0], filename) Laurent@2111: andrej@2360: Laurent@2111: class EtherlabLibrary(POULibrary): Laurent@2111: def GetLibraryPath(self): Laurent@2111: return GetLocalPath("pous.xml") Laurent@2111: Laurent@2111: def Generate_C(self, buildpath, varlist, IECCFLAGS): Laurent@2111: etherlab_ext_file = open(GetLocalPath("etherlab_ext.c"), 'r') Laurent@2111: etherlab_ext_code = etherlab_ext_file.read() Laurent@2111: etherlab_ext_file.close() andrej@2355: Laurent@2111: Gen_etherlabfile_path = os.path.join(buildpath, "etherlab_ext.c") andrej@2363: ethelabfile = open(Gen_etherlabfile_path, 'w') Laurent@2111: ethelabfile.write(etherlab_ext_code) Laurent@2111: ethelabfile.close() andrej@2355: Edouard@2152: runtimefile_path = os.path.join(os.path.split(__file__)[0], "runtime_etherlab.py") andrej@2355: return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", Laurent@2111: ("runtime_etherlab.py", file(GetLocalPath("runtime_etherlab.py")))) andrej@2355: andrej@2356: # -------------------------------------------------- Laurent@2111: # Ethercat MASTER andrej@2356: # -------------------------------------------------- Laurent@2111: andrej@2370: andrej@2355: EtherCATConfigParser = GenerateParserFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATConfig.xsd")) Laurent@2111: andrej@2360: Laurent@2111: def sort_commands(x, y): Laurent@2111: if x["Index"] == y["Index"]: Laurent@2111: return cmp(x["Subindex"], y["Subindex"]) Laurent@2111: return cmp(x["Index"], y["Index"]) Laurent@2111: andrej@2370: Laurent@2157: cls = EtherCATConfigParser.GetElementClass("Slave", "Config") Laurent@2111: if cls: andrej@2355: Laurent@2111: def getType(self): Laurent@2111: slave_info = self.getInfo() Laurent@2111: return {"device_type": slave_info.getName(), Laurent@2111: "vendor": GenerateHexDecValue(slave_info.getVendorId()), Laurent@2111: "product_code": GenerateHexDecValue(slave_info.getProductCode(), 16), Laurent@2111: "revision_number": GenerateHexDecValue(slave_info.getRevisionNo(), 16)} Laurent@2111: setattr(cls, "getType", getType) Laurent@2111: Laurent@2111: def setType(self, type_infos): Laurent@2111: slave_info = self.getInfo() Laurent@2111: slave_info.setName(type_infos["device_type"]) Laurent@2111: slave_info.setVendorId(ExtractHexDecValue(type_infos["vendor"])) Laurent@2111: slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"])) Laurent@2111: slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"])) Laurent@2111: setattr(cls, "setType", setType) andrej@2355: Laurent@2111: def getInitCmds(self, create_default=False): Laurent@2111: Mailbox = self.getMailbox() Laurent@2111: if Mailbox is None: Laurent@2111: if create_default: Laurent@2111: self.addMailbox() Laurent@2111: Mailbox = self.getMailbox() Laurent@2111: else: Laurent@2111: return None Laurent@2111: CoE = Mailbox.getCoE() Laurent@2111: if CoE is None: Laurent@2111: if create_default: Laurent@2111: Mailbox.addCoE() Laurent@2111: CoE = Mailbox.getCoE() Laurent@2111: else: Laurent@2111: return None Laurent@2111: InitCmds = CoE.getInitCmds() Laurent@2111: if InitCmds is None and create_default: Laurent@2111: CoE.addInitCmds() Laurent@2111: InitCmds = CoE.getInitCmds() Laurent@2111: return InitCmds Laurent@2111: setattr(cls, "getInitCmds", getInitCmds) andrej@2355: Laurent@2111: def getStartupCommands(self): Laurent@2111: pos = self.getInfo().getPhysAddr() Laurent@2111: InitCmds = self.getInitCmds() Laurent@2111: if InitCmds is None: Laurent@2111: return [] Laurent@2111: commands = [] Laurent@2111: for idx, InitCmd in enumerate(InitCmds.getInitCmd()): Laurent@2111: comment = InitCmd.getComment() Laurent@2111: if comment is None: Laurent@2111: comment = "" Laurent@2111: commands.append({ Laurent@2111: "command_idx": idx, Laurent@2111: "Position": pos, Laurent@2111: "Index": InitCmd.getIndex(), Laurent@2111: "Subindex": InitCmd.getSubIndex(), Laurent@2111: "Value": InitCmd.getData(), Laurent@2111: "Description": comment}) Laurent@2111: commands.sort(sort_commands) Laurent@2111: return commands Laurent@2111: setattr(cls, "getStartupCommands", getStartupCommands) andrej@2355: Laurent@2111: def appendStartupCommand(self, command_infos): Laurent@2111: InitCmds = self.getInitCmds(True) Laurent@2157: command = EtherCATConfigParser.CreateElement("InitCmd", "InitCmds", 1) Laurent@2157: InitCmds.appendInitCmd(command) Laurent@2111: command.setIndex(command_infos["Index"]) Laurent@2111: command.setSubIndex(command_infos["Subindex"]) Laurent@2111: command.setData(command_infos["Value"]) Laurent@2111: command.setComment(command_infos["Description"]) Laurent@2111: return len(InitCmds.getInitCmd()) - 1 Laurent@2111: setattr(cls, "appendStartupCommand", appendStartupCommand) andrej@2355: Laurent@2111: def setStartupCommand(self, command_infos): Laurent@2111: InitCmds = self.getInitCmds() Laurent@2111: if InitCmds is not None: Laurent@2111: commands = InitCmds.getInitCmd() Laurent@2111: if command_infos["command_idx"] < len(commands): Laurent@2111: command = commands[command_infos["command_idx"]] Laurent@2111: command.setIndex(command_infos["Index"]) Laurent@2111: command.setSubIndex(command_infos["Subindex"]) Laurent@2111: command.setData(command_infos["Value"]) Laurent@2111: command.setComment(command_infos["Description"]) Laurent@2111: setattr(cls, "setStartupCommand", setStartupCommand) andrej@2355: Laurent@2111: def removeStartupCommand(self, command_idx): Laurent@2111: InitCmds = self.getInitCmds() Laurent@2111: if InitCmds is not None: Laurent@2111: if command_idx < len(InitCmds.getInitCmd()): Laurent@2111: InitCmds.removeInitCmd(command_idx) Laurent@2111: setattr(cls, "removeStartupCommand", removeStartupCommand) Laurent@2111: Laurent@2111: ProcessVariablesXSD = """ Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: Laurent@2111: """ Laurent@2111: andrej@2355: ProcessVariablesParser = GenerateParserFromXSDstring(ProcessVariablesXSD) Laurent@2111: andrej@2360: andrej@2397: class _EthercatCTN(object): Edouard@2152: Laurent@2111: CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")] Laurent@2111: if HAS_MCL: Laurent@2111: CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave")) Laurent@2111: EditorType = MasterEditor andrej@2355: Laurent@2111: def __init__(self): Laurent@2111: config_filepath = self.ConfigFileName() Laurent@2111: config_is_saved = False Laurent@2160: self.Config = None Laurent@2111: if os.path.isfile(config_filepath): Laurent@2111: config_xmlfile = open(config_filepath, 'r') Laurent@2160: try: Laurent@2160: self.Config, error = \ Laurent@2160: EtherCATConfigParser.LoadXMLString(config_xmlfile.read()) Laurent@2160: if error is None: Laurent@2160: config_is_saved = True Laurent@2160: except Exception, e: Laurent@2160: error = e.message Laurent@2111: config_xmlfile.close() andrej@2355: Laurent@2160: if error is not None: Laurent@2160: self.GetCTRoot().logger.write_error( andrej@2404: _("Couldn't load %s network configuration file.") % self.CTNName()) andrej@2355: Laurent@2160: if self.Config is None: Laurent@2157: self.Config = EtherCATConfigParser.CreateElement("EtherCATConfig") andrej@2355: Laurent@2111: process_filepath = self.ProcessVariablesFileName() Laurent@2111: process_is_saved = False Laurent@2160: self.ProcessVariables = None Laurent@2111: if os.path.isfile(process_filepath): Laurent@2111: process_xmlfile = open(process_filepath, 'r') Laurent@2160: try: Laurent@2160: self.ProcessVariables, error = \ Laurent@2160: ProcessVariablesParser.LoadXMLString(process_xmlfile.read()) Laurent@2160: if error is None: Laurent@2160: process_is_saved = True Laurent@2160: except Exception, e: Laurent@2160: error = e.message Laurent@2111: process_xmlfile.close() andrej@2355: Laurent@2160: if error is not None: Laurent@2160: self.GetCTRoot().logger.write_error( andrej@2404: _("Couldn't load %s network process variables file.") % self.CTNName()) andrej@2355: Laurent@2160: if self.ProcessVariables is None: Laurent@2157: self.ProcessVariables = ProcessVariablesParser.CreateElement("ProcessVariables") andrej@2355: Laurent@2111: if config_is_saved and process_is_saved: Laurent@2111: self.CreateBuffer(True) Laurent@2111: else: Laurent@2111: self.CreateBuffer(False) Laurent@2111: self.OnCTNSave() andrej@2355: Edouard@2152: # ----------- call ethercat mng. function -------------- Edouard@2152: self.CommonMethod = _CommonSlave(self) andrej@2355: Laurent@2149: def GetIconName(self): Laurent@2149: return "Ethercat" andrej@2355: Laurent@2111: def GetContextualMenuItems(self): Laurent@2111: return [("Add Ethercat Slave", "Add Ethercat Slave to Master", self.OnAddEthercatSlave)] andrej@2355: Laurent@2111: def OnAddEthercatSlave(self, event): Laurent@2111: app_frame = self.GetCTRoot().AppFrame andrej@2355: dialog = BrowseValuesLibraryDialog(app_frame, andrej@2381: "Ethercat Slave Type", andrej@2381: self.GetSlaveTypesLibrary()) Laurent@2111: if dialog.ShowModal() == wx.ID_OK: Laurent@2111: type_infos = dialog.GetValueInfos() Laurent@2137: device, module_extra_params = self.GetModuleInfos(type_infos) Laurent@2111: if device is not None: Laurent@2111: if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): Laurent@2111: ConfNodeType = "EthercatCIA402Slave" Laurent@2111: else: Laurent@2111: ConfNodeType = "EthercatSlave" Laurent@2111: new_child = self.CTNAddChild("%s_0" % ConfNodeType, ConfNodeType) Laurent@2111: new_child.SetParamsAttribute("SlaveParams.Type", type_infos) Laurent@2111: self.CTNRequestSave() Laurent@2111: new_child._OpenView() Laurent@2111: app_frame._Refresh(TITLE, FILEMENU, PROJECTTREE) Laurent@2111: dialog.Destroy() andrej@2355: Laurent@2111: def ExtractHexDecValue(self, value): Laurent@2111: return ExtractHexDecValue(value) Laurent@2111: Laurent@2111: def GetSizeOfType(self, type): Laurent@2111: return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None) Laurent@2111: Laurent@2111: def ConfigFileName(self): Laurent@2111: return os.path.join(self.CTNPath(), "config.xml") andrej@2355: Laurent@2111: def ProcessVariablesFileName(self): Laurent@2111: return os.path.join(self.CTNPath(), "process_variables.xml") andrej@2355: Laurent@2111: def FilterSlave(self, slave, vendor=None, slave_pos=None, slave_profile=None): Laurent@2111: if slave_pos is not None and slave.getInfo().getPhysAddr() != slave_pos: Laurent@2111: return False Laurent@2111: type_infos = slave.getType() Laurent@2111: if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: Laurent@2111: return False Laurent@2137: device, module_extra_params = self.GetModuleInfos(type_infos) Laurent@2111: if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): Laurent@2111: return False Laurent@2111: return True Laurent@2111: Laurent@2124: def GetSlaveName(self, slave_pos): Laurent@2124: CTNChild = self.GetChildByIECLocation((slave_pos,)) Laurent@2124: if CTNChild is not None: Laurent@2124: return CTNChild.CTNName() Laurent@2124: return self.CTNName() Laurent@2124: Laurent@2111: def GetSlaves(self, vendor=None, slave_pos=None, slave_profile=None): Laurent@2111: slaves = [] Laurent@2111: for slave in self.Config.getConfig().getSlave(): Laurent@2111: if self.FilterSlave(slave, vendor, slave_pos, slave_profile): Laurent@2111: slaves.append(slave.getInfo().getPhysAddr()) Laurent@2111: slaves.sort() Laurent@2111: return slaves Laurent@2111: Laurent@2111: def GetSlave(self, slave_pos): Laurent@2111: for slave in self.Config.getConfig().getSlave(): Laurent@2111: slave_info = slave.getInfo() Laurent@2111: if slave_info.getPhysAddr() == slave_pos: Laurent@2111: return slave Laurent@2111: return None Laurent@2111: Laurent@2111: def GetStartupCommands(self, vendor=None, slave_pos=None, slave_profile=None): Laurent@2111: commands = [] Laurent@2111: for slave in self.Config.getConfig().getSlave(): Laurent@2111: if self.FilterSlave(slave, vendor, slave_pos, slave_profile): Laurent@2111: commands.append((slave.getInfo().getPhysAddr(), slave.getStartupCommands())) Laurent@2111: commands.sort() Laurent@2111: return reduce(lambda x, y: x + y[1], commands, []) andrej@2355: Laurent@2111: def AppendStartupCommand(self, command_infos): Laurent@2111: slave = self.GetSlave(command_infos["Position"]) Laurent@2111: if slave is not None: Laurent@2111: command_idx = slave.appendStartupCommand(command_infos) Laurent@2111: self.BufferModel() Laurent@2111: return command_idx Laurent@2111: return None andrej@2355: Laurent@2111: def SetStartupCommandInfos(self, command_infos): Laurent@2111: slave = self.GetSlave(command_infos["Position"]) Laurent@2111: if slave is not None: Laurent@2111: slave.setStartupCommand(command_infos) Laurent@2111: self.BufferModel() andrej@2355: Laurent@2111: def RemoveStartupCommand(self, slave_pos, command_idx, buffer=True): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: slave.removeStartupCommand(command_idx) Laurent@2111: if buffer: Laurent@2111: self.BufferModel() andrej@2355: Laurent@2111: def SetProcessVariables(self, variables): Laurent@2111: vars = [] Laurent@2111: for var in variables: Laurent@2157: variable = ProcessVariablesParser.CreateElement("variable", "ProcessVariables") Laurent@2111: variable.setName(var["Name"]) Laurent@2111: variable.setComment(var["Description"]) Laurent@2111: if var["ReadFrom"] != "": Laurent@2111: position, index, subindex = var["ReadFrom"] Laurent@2111: if variable.getReadFrom() is None: Laurent@2111: variable.addReadFrom() Laurent@2111: read_from = variable.getReadFrom() Laurent@2111: read_from.setPosition(position) Laurent@2111: read_from.setIndex(index) Laurent@2111: read_from.setSubIndex(subindex) Laurent@2111: elif variable.getReadFrom() is not None: Laurent@2111: variable.deleteReadFrom() Laurent@2111: if var["WriteTo"] != "": Laurent@2111: position, index, subindex = var["WriteTo"] Laurent@2111: if variable.getWriteTo() is None: Laurent@2111: variable.addWriteTo() Laurent@2111: write_to = variable.getWriteTo() Laurent@2111: write_to.setPosition(position) Laurent@2111: write_to.setIndex(index) Laurent@2111: write_to.setSubIndex(subindex) Laurent@2111: elif variable.getWriteTo() is not None: Laurent@2111: variable.deleteWriteTo() Laurent@2111: vars.append(variable) Laurent@2111: self.ProcessVariables.setvariable(vars) Laurent@2111: self.BufferModel() andrej@2355: Laurent@2111: def GetProcessVariables(self): Laurent@2111: variables = [] Laurent@2111: idx = 0 Laurent@2111: for variable in self.ProcessVariables.getvariable(): Laurent@2111: var = {"Name": variable.getName(), Laurent@2111: "Number": idx, Laurent@2111: "Description": variable.getComment()} Laurent@2111: read_from = variable.getReadFrom() Laurent@2111: if read_from is not None: Laurent@2111: var["ReadFrom"] = (read_from.getPosition(), Laurent@2111: read_from.getIndex(), Laurent@2111: read_from.getSubIndex()) Laurent@2111: else: Laurent@2111: var["ReadFrom"] = "" Laurent@2111: write_to = variable.getWriteTo() Laurent@2111: if write_to is not None: Laurent@2111: var["WriteTo"] = (write_to.getPosition(), andrej@2380: write_to.getIndex(), andrej@2380: write_to.getSubIndex()) Laurent@2111: else: Laurent@2111: var["WriteTo"] = "" Laurent@2111: variables.append(var) Laurent@2111: idx += 1 Laurent@2111: return variables andrej@2355: Laurent@2111: def _ScanNetwork(self): Laurent@2111: app_frame = self.GetCTRoot().AppFrame andrej@2355: Laurent@2111: execute = True Laurent@2111: if len(self.Children) > 0: andrej@2381: dialog = wx.MessageDialog( andrej@2381: app_frame, andrej@2355: _("The current network configuration will be deleted.\nDo you want to continue?"), andrej@2355: _("Scan Network"), andrej@2367: wx.YES_NO | wx.ICON_QUESTION) Laurent@2111: execute = dialog.ShowModal() == wx.ID_YES Laurent@2111: dialog.Destroy() andrej@2355: Laurent@2111: if execute: andrej@2366: error, returnVal = self.RemoteExec(SCAN_COMMAND, returnVal=None) Laurent@2111: if error != 0: andrej@2367: dialog = wx.MessageDialog(app_frame, returnVal, "Error", wx.OK | wx.ICON_ERROR) Laurent@2111: dialog.ShowModal() Laurent@2111: dialog.Destroy() Laurent@2111: elif returnVal is not None: Laurent@2111: for child in self.IECSortedChildren(): Laurent@2111: self._doRemoveChild(child) andrej@2355: Laurent@2111: for slave in returnVal: Laurent@2111: type_infos = { Laurent@2111: "vendor": slave["vendor_id"], Laurent@2111: "product_code": slave["product_code"], andrej@2363: "revision_number": slave["revision_number"], Laurent@2111: } Laurent@2137: device, module_extra_params = self.GetModuleInfos(type_infos) Laurent@2111: if device is not None: Laurent@2111: if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): Laurent@2111: CTNType = "EthercatCIA402Slave" Laurent@2111: else: Laurent@2111: CTNType = "EthercatSlave" Laurent@2111: self.CTNAddChild("slave%s" % slave["idx"], CTNType, slave["idx"]) Laurent@2111: self.SetSlaveAlias(slave["idx"], slave["alias"]) Laurent@2111: type_infos["device_type"] = device.getType().getcontent() Laurent@2111: self.SetSlaveType(slave["idx"], type_infos) andrej@2355: Laurent@2127: if app_frame: Laurent@2127: app_frame.RefreshProjectTree() andrej@2355: Laurent@2111: def CTNAddChild(self, CTNName, CTNType, IEC_Channel=0): Laurent@2111: """ Laurent@2111: Create the confnodes that may be added as child to this node self Laurent@2111: @param CTNType: string desining the confnode class name (get name from CTNChildrenTypes) Laurent@2111: @param CTNName: string for the name of the confnode instance Laurent@2111: """ Laurent@2111: newConfNodeOpj = ConfigTreeNode.CTNAddChild(self, CTNName, CTNType, IEC_Channel) andrej@2355: Laurent@2111: slave = self.GetSlave(newConfNodeOpj.BaseParams.getIEC_Channel()) Laurent@2111: if slave is None: Laurent@2157: slave = EtherCATConfigParser.CreateElement("Slave", "Config") Laurent@2157: self.Config.getConfig().appendSlave(slave) Laurent@2111: slave_infos = slave.getInfo() Laurent@2111: slave_infos.setName("undefined") Laurent@2111: slave_infos.setPhysAddr(newConfNodeOpj.BaseParams.getIEC_Channel()) Laurent@2111: slave_infos.setAutoIncAddr(0) Laurent@2111: self.BufferModel() Laurent@2111: self.OnCTNSave() andrej@2355: Laurent@2111: return newConfNodeOpj Laurent@2111: Laurent@2111: def _doRemoveChild(self, CTNInstance): Laurent@2111: slave_pos = CTNInstance.GetSlavePos() Laurent@2111: config = self.Config.getConfig() Laurent@2111: for idx, slave in enumerate(config.getSlave()): Laurent@2111: slave_infos = slave.getInfo() Laurent@2111: if slave_infos.getPhysAddr() == slave_pos: Laurent@2111: config.removeSlave(idx) Laurent@2111: self.BufferModel() Laurent@2111: self.OnCTNSave() Laurent@2111: ConfigTreeNode._doRemoveChild(self, CTNInstance) Laurent@2111: Laurent@2111: def SetSlavePosition(self, slave_pos, new_pos): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: slave_info = slave.getInfo() Laurent@2111: slave_info.setPhysAddr(new_pos) Laurent@2111: for variable in self.ProcessVariables.getvariable(): Laurent@2111: read_from = variable.getReadFrom() Laurent@2111: if read_from is not None and read_from.getPosition() == slave_pos: Laurent@2111: read_from.setPosition(new_pos) Laurent@2111: write_to = variable.getWriteTo() Laurent@2111: if write_to is not None and write_to.getPosition() == slave_pos: Laurent@2111: write_to.setPosition(new_pos) Laurent@2111: self.CreateBuffer(True) Laurent@2147: self.CTNRequestSave() Laurent@2111: if self._View is not None: Laurent@2111: self._View.RefreshView() Laurent@2111: self._View.RefreshBuffer() andrej@2355: Laurent@2111: def GetSlaveAlias(self, slave_pos): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: slave_info = slave.getInfo() Laurent@2111: return slave_info.getAutoIncAddr() Laurent@2111: return None andrej@2355: Laurent@2111: def SetSlaveAlias(self, slave_pos, alias): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: slave_info = slave.getInfo() Laurent@2111: slave_info.setAutoIncAddr(alias) Laurent@2111: self.BufferModel() andrej@2355: Laurent@2111: def GetSlaveType(self, slave_pos): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: return slave.getType() Laurent@2111: return None andrej@2355: Laurent@2111: def SetSlaveType(self, slave_pos, type_infos): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: slave.setType(type_infos) Laurent@2111: self.BufferModel() andrej@2355: Laurent@2111: def GetSlaveInfos(self, slave_pos): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: type_infos = slave.getType() Laurent@2137: device, module_extra_params = self.GetModuleInfos(type_infos) Laurent@2111: if device is not None: Laurent@2111: infos = type_infos.copy() Laurent@2111: infos.update({"physics": device.getPhysics(), Laurent@2111: "sync_managers": device.GetSyncManagers(), Laurent@2111: "entries": self.GetSlaveVariables(device)}) Laurent@2111: return infos Laurent@2111: return None andrej@2355: Laurent@2111: def GetSlaveVariables(self, slave_pos=None, limits=None, device=None): Laurent@2111: if device is None and slave_pos is not None: Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: type_infos = slave.getType() Laurent@2137: device, module_extra_params = self.GetModuleInfos(type_infos) Laurent@2111: if device is not None: Laurent@2111: entries = device.GetEntriesList(limits) Laurent@2111: entries_list = entries.items() Laurent@2111: entries_list.sort() Laurent@2111: entries = [] Laurent@2111: current_index = None andrej@2403: current_entry = {} Laurent@2111: for (index, subindex), entry in entries_list: Laurent@2111: entry["children"] = [] Laurent@2111: if slave_pos is not None: Laurent@2111: entry["Position"] = str(slave_pos) Laurent@2111: if index != current_index: Laurent@2111: current_index = index Laurent@2111: current_entry = entry Laurent@2111: entries.append(entry) andrej@2403: elif current_entry: Laurent@2111: current_entry["children"].append(entry) Laurent@2111: else: Laurent@2111: entries.append(entry) Laurent@2111: return entries Laurent@2111: return [] andrej@2355: Laurent@2111: def GetSlaveVariableDataType(self, slave_pos, index, subindex): Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2137: device, module_extra_params = self.GetModuleInfos(slave.getType()) Laurent@2111: if device is not None: Laurent@2111: entries = device.GetEntriesList() Laurent@2111: entry_infos = entries.get((index, subindex)) Laurent@2111: if entry_infos is not None: Laurent@2111: return entry_infos["Type"] Laurent@2111: return None andrej@2355: Laurent@2111: def GetNodesVariables(self, vendor=None, slave_pos=None, slave_profile=None, limits=None): Laurent@2111: entries = [] Laurent@2111: for slave_position in self.GetSlaves(): Laurent@2111: if slave_pos is not None and slave_position != slave_pos: Laurent@2111: continue Laurent@2111: slave = self.GetSlave(slave_position) Laurent@2111: type_infos = slave.getType() Laurent@2111: if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: Laurent@2111: continue Laurent@2137: device, module_extra_params = self.GetModuleInfos(type_infos) Laurent@2111: if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): Laurent@2111: continue Laurent@2111: entries.extend(self.GetSlaveVariables(slave_position, limits, device)) Laurent@2111: return entries andrej@2355: Laurent@2111: def GetModuleInfos(self, type_infos): Laurent@2111: return self.CTNParent.GetModuleInfos(type_infos) andrej@2355: Laurent@2111: def GetSlaveTypesLibrary(self, profile_filter=None): Laurent@2111: return self.CTNParent.GetModulesLibrary(profile_filter) andrej@2355: Laurent@2111: def GetLibraryVendors(self): Laurent@2111: return self.CTNParent.GetVendors() andrej@2355: Laurent@2111: def GetDeviceLocationTree(self, slave_pos, current_location, device_name): Laurent@2111: slave = self.GetSlave(slave_pos) andrej@2355: vars = [] Laurent@2111: if slave is not None: Laurent@2111: type_infos = slave.getType() andrej@2355: Laurent@2137: device, module_extra_params = self.GetModuleInfos(type_infos) Laurent@2111: if device is not None: Laurent@2111: sync_managers = [] Laurent@2111: for sync_manager in device.getSm(): Laurent@2111: sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte()) Laurent@2111: sync_manager_direction = sync_manager_control_byte & 0x0c Laurent@2111: if sync_manager_direction: Laurent@2111: sync_managers.append(LOCATION_VAR_OUTPUT) Laurent@2111: else: Laurent@2111: sync_managers.append(LOCATION_VAR_INPUT) andrej@2355: Laurent@2111: entries = device.GetEntriesList().items() Laurent@2111: entries.sort() Laurent@2111: for (index, subindex), entry in entries: Laurent@2111: var_size = self.GetSizeOfType(entry["Type"]) Laurent@2111: if var_size is not None: Laurent@2111: var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None) Laurent@2111: if var_class is not None: Laurent@2111: if var_class == LOCATION_VAR_INPUT: Laurent@2111: var_dir = "%I" Laurent@2111: else: andrej@2355: var_dir = "%Q" andrej@2355: andrej@2380: vars.append({ andrej@2380: "name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]), andrej@2380: "type": var_class, andrej@2380: "size": var_size, andrej@2380: "IEC_type": entry["Type"], andrej@2380: "var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex), andrej@2380: "location": "%s%s%s" % (var_dir, var_size, ".".join(map(str, current_location + andrej@2380: (index, subindex)))), andrej@2380: "description": "", andrej@2380: "children": [], andrej@2380: }) andrej@2355: Laurent@2111: return vars andrej@2355: Laurent@2111: def CTNTestModified(self): andrej@2355: return self.ChangesToSave or not self.ModelIsSaved() Laurent@2111: Laurent@2133: def OnCTNSave(self, from_project_path=None): Laurent@2111: config_filepath = self.ConfigFileName() andrej@2355: andrej@2363: config_xmlfile = open(config_filepath, "w") Laurent@2157: config_xmlfile.write(etree.tostring( andrej@2355: self.Config, andrej@2355: pretty_print=True, andrej@2355: xml_declaration=True, Laurent@2157: encoding='utf-8')) Laurent@2111: config_xmlfile.close() andrej@2355: Laurent@2111: process_filepath = self.ProcessVariablesFileName() andrej@2355: andrej@2363: process_xmlfile = open(process_filepath, "w") Laurent@2157: process_xmlfile.write(etree.tostring( andrej@2355: self.ProcessVariables, andrej@2355: pretty_print=True, andrej@2355: xml_declaration=True, Laurent@2157: encoding='utf-8')) Laurent@2111: process_xmlfile.close() andrej@2355: Laurent@2111: self.Buffer.CurrentSaved() Laurent@2111: return True Laurent@2111: Laurent@2111: def GetProcessVariableName(self, location, var_type): Laurent@2111: return "__M%s_%s" % (self.GetSizeOfType(var_type), "_".join(map(str, location))) Laurent@2111: Laurent@2111: def _Generate_C(self, buildpath, locations): Laurent@2111: current_location = self.GetCurrentLocation() Laurent@2111: # define a unique name for the generated C file andrej@2391: location_str = "_".join(map(str, current_location)) andrej@2355: andrej@2358: Gen_Ethercatfile_path = os.path.join(buildpath, "ethercat_%s.c" % location_str) andrej@2355: Laurent@2111: self.FileGenerator = _EthercatCFileGenerator(self) andrej@2355: Laurent@2111: LocationCFilesAndCFLAGS, LDFLAGS, extra_files = ConfigTreeNode._Generate_C(self, buildpath, locations) andrej@2355: Laurent@2111: for idx, variable in enumerate(self.ProcessVariables.getvariable()): Laurent@2111: name = None Laurent@2111: var_type = None Laurent@2111: read_from = variable.getReadFrom() Laurent@2111: write_to = variable.getWriteTo() Laurent@2111: if read_from is not None: Laurent@2111: pos = read_from.getPosition() Laurent@2111: index = read_from.getIndex() Laurent@2111: subindex = read_from.getSubIndex() Laurent@2111: location = current_location + (idx, ) Laurent@2111: var_type = self.GetSlaveVariableDataType(pos, index, subindex) Laurent@2111: name = self.FileGenerator.DeclareVariable( Laurent@2111: pos, index, subindex, var_type, "I", Laurent@2111: self.GetProcessVariableName(location, var_type)) Laurent@2111: if write_to is not None: Laurent@2111: pos = write_to.getPosition() Laurent@2111: index = write_to.getIndex() Laurent@2111: subindex = write_to.getSubIndex() Laurent@2111: if name is None: Laurent@2111: location = current_location + (idx, ) Laurent@2111: var_type = self.GetSlaveVariableDataType(pos, index, subindex) Laurent@2111: name = self.GetProcessVariableName(location, var_type) Laurent@2111: self.FileGenerator.DeclareVariable( Laurent@2111: pos, index, subindex, var_type, "Q", name, True) andrej@2355: Laurent@2111: self.FileGenerator.GenerateCFile(Gen_Ethercatfile_path, location_str, self.BaseParams.getIEC_Channel()) andrej@2355: andrej@2381: LocationCFilesAndCFLAGS.insert( andrej@2381: 0, andrej@2355: (current_location, andrej@2358: [(Gen_Ethercatfile_path, '"-I%s"' % os.path.abspath(self.GetCTRoot().GetIECLibPath()))], Laurent@2111: True)) Edouard@2112: LDFLAGS.append("-lethercat_rtdm -lrtdm") andrej@2355: Laurent@2111: return LocationCFilesAndCFLAGS, LDFLAGS, extra_files Laurent@2111: Laurent@2111: ConfNodeMethods = [ andrej@2375: { andrej@2375: "bitmap": "ScanNetwork", andrej@2375: "name": _("Scan Network"), andrej@2375: "tooltip": _("Scan Network"), andrej@2375: "method": "_ScanNetwork", andrej@2375: }, Laurent@2111: ] Laurent@2111: Laurent@2111: def CTNGenerate_C(self, buildpath, locations): Laurent@2111: current_location = self.GetCurrentLocation() andrej@2355: Laurent@2111: slaves = self.GetSlaves() Laurent@2111: for slave_pos in slaves: Laurent@2111: slave = self.GetSlave(slave_pos) Laurent@2111: if slave is not None: Laurent@2111: self.FileGenerator.DeclareSlave(slave_pos, slave) andrej@2355: Laurent@2111: for location in locations: Laurent@2111: loc = location["LOC"][len(current_location):] Laurent@2111: slave_pos = loc[0] Laurent@2111: if slave_pos in slaves and len(loc) == 3 and location["DIR"] != "M": Laurent@2111: self.FileGenerator.DeclareVariable( Laurent@2111: slave_pos, loc[1], loc[2], location["IEC_TYPE"], location["DIR"], location["NAME"]) andrej@2355: andrej@2363: return [], "", False andrej@2355: andrej@2356: # ------------------------------------------------------------------------------- Laurent@2111: # Current Buffering Management Functions andrej@2356: # ------------------------------------------------------------------------------- Laurent@2111: Laurent@2111: def Copy(self, model): andrej@2394: """Return a copy of the config""" Laurent@2157: return deepcopy(model) andrej@2355: Laurent@2111: def CreateBuffer(self, saved): Laurent@2157: self.Buffer = UndoBuffer( andrej@2355: (EtherCATConfigParser.Dumps(self.Config), andrej@2355: ProcessVariablesParser.Dumps(self.ProcessVariables)), Laurent@2157: saved) andrej@2355: Laurent@2111: def BufferModel(self): Laurent@2157: self.Buffer.Buffering( andrej@2355: (EtherCATConfigParser.Dumps(self.Config), Laurent@2157: ProcessVariablesParser.Dumps(self.ProcessVariables))) andrej@2355: Laurent@2111: def ModelIsSaved(self): Laurent@2111: if self.Buffer is not None: Laurent@2111: return self.Buffer.IsCurrentSaved() Laurent@2111: else: Laurent@2111: return True Laurent@2111: Laurent@2111: def LoadPrevious(self): Laurent@2157: config, process_variables = self.Buffer.Previous() Laurent@2157: self.Config = EtherCATConfigParser.Loads(config) Laurent@2157: self.ProcessVariables = ProcessVariablesParser.Loads(process_variables) andrej@2355: Laurent@2111: def LoadNext(self): Laurent@2157: config, process_variables = self.Buffer.Next() Laurent@2157: self.Config = EtherCATConfigParser.Loads(config) Laurent@2157: self.ProcessVariables = ProcessVariablesParser.Loads(process_variables) andrej@2355: Laurent@2111: def GetBufferState(self): Laurent@2111: first = self.Buffer.IsFirst() Laurent@2111: last = self.Buffer.IsLast() Laurent@2111: return not first, not last