etherlab/etherlab.py
changeset 2098 392791b5cc04
parent 2097 58d07e039896
child 2099 ea5384ab152c
equal deleted inserted replaced
2097:58d07e039896 2098:392791b5cc04
     7 
     7 
     8 from xmlclass import *
     8 from xmlclass import *
     9 from POULibrary import POULibrary
     9 from POULibrary import POULibrary
    10 from ConfigTreeNode import ConfigTreeNode
    10 from ConfigTreeNode import ConfigTreeNode
    11 from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    11 from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    12 from ConfigEditor import NodeEditor, CIA402NodeEditor, LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
    12 from ConfigEditor import NodeEditor, CIA402NodeEditor, MasterEditor, LibraryEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
    13 
    13 
    14 try:
    14 try:
    15     from MotionLibrary import Headers, AxisXSD
    15     from MotionLibrary import Headers, AxisXSD
    16     HAS_MCL = True
    16     HAS_MCL = True
    17 except:
    17 except:
   158         
   158         
   159         return value, refresh
   159         return value, refresh
   160         
   160         
   161     def GetSlaveInfos(self):
   161     def GetSlaveInfos(self):
   162         return self.CTNParent.GetSlaveInfos(self.GetSlavePos())
   162         return self.CTNParent.GetSlaveInfos(self.GetSlavePos())
       
   163     
       
   164     def GetSlaveVariables(self, limits):
       
   165         return self.CTNParent.GetSlaveVariables(self.GetSlavePos(), limits)
   163     
   166     
   164     def GetVariableLocationTree(self):
   167     def GetVariableLocationTree(self):
   165         return  {"name": self.BaseParams.getName(),
   168         return  {"name": self.BaseParams.getName(),
   166                  "type": LOCATION_CONFNODE,
   169                  "type": LOCATION_CONFNODE,
   167                  "location": self.GetFullIEC_Channel(),
   170                  "location": self.GetFullIEC_Channel(),
   468     elif base == 16:
   471     elif base == 16:
   469         return "#x%.8x" % value
   472         return "#x%.8x" % value
   470     else:
   473     else:
   471         raise ValueError, "Not supported base"
   474         raise ValueError, "Not supported base"
   472 
   475 
       
   476 def sort_commands(x, y):
       
   477     if x["Index"] == y["Index"]:
       
   478         return cmp(x["Subindex"], y["Subindex"])
       
   479     return cmp(x["Index"], y["Index"])
       
   480 
   473 cls = EtherCATConfigClasses.get("Config_Slave", None)
   481 cls = EtherCATConfigClasses.get("Config_Slave", None)
   474 if cls:
   482 if cls:
   475     
   483     
   476     def getType(self):
   484     def getType(self):
   477         slave_info = self.getInfo()
   485         slave_info = self.getInfo()
   486         slave_info.setName(type_infos["device_type"])
   494         slave_info.setName(type_infos["device_type"])
   487         slave_info.setVendorId(ExtractHexDecValue(type_infos["vendor"]))
   495         slave_info.setVendorId(ExtractHexDecValue(type_infos["vendor"]))
   488         slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"]))
   496         slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"]))
   489         slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"]))
   497         slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"]))
   490     setattr(cls, "setType", setType)
   498     setattr(cls, "setType", setType)
   491 
   499     
   492 class _EthercatCTN:
   500     def getInitCmds(self, create_default=False):
   493     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   501         Mailbox = self.getMailbox()
       
   502         if Mailbox is None:
       
   503             if create_default:
       
   504                 self.addMailbox()
       
   505                 Mailbox = self.getMailbox()
       
   506             else:
       
   507                 return None
       
   508         CoE = Mailbox.getCoE()
       
   509         if CoE is None:
       
   510             if create_default:
       
   511                 Mailbox.addCoE()
       
   512                 CoE = Mailbox.getCoE()
       
   513             else:
       
   514                 return None
       
   515         InitCmds = CoE.getInitCmds()
       
   516         if InitCmds is None and create_default:
       
   517             CoE.addInitCmds()
       
   518             InitCmds = CoE.getInitCmds()
       
   519         return InitCmds
       
   520     setattr(cls, "getInitCmds", getInitCmds)
       
   521     
       
   522     def getStartupCommands(self):
       
   523         pos = self.getInfo().getPhysAddr()
       
   524         InitCmds = self.getInitCmds()
       
   525         if InitCmds is None:
       
   526             return []
       
   527         commands = []
       
   528         for idx, InitCmd in enumerate(InitCmds.getInitCmd()):
       
   529             comment = InitCmd.getComment()
       
   530             if comment is None:
       
   531                 comment = ""
       
   532             commands.append({
       
   533                 "command_idx": idx,
       
   534                 "Position": pos,
       
   535                 "Index": InitCmd.getIndex(),
       
   536                 "Subindex": InitCmd.getSubIndex(),
       
   537                 "Value": InitCmd.getData(),
       
   538                 "Description": comment})
       
   539         commands.sort(sort_commands)
       
   540         return commands
       
   541     setattr(cls, "getStartupCommands", getStartupCommands)
       
   542     
       
   543     def appendStartupCommand(self, command_infos):
       
   544         InitCmds = self.getInitCmds(True)
       
   545         command = EtherCATConfigClasses["InitCmds_InitCmd"]()
       
   546         command.setIndex(command_infos["Index"])
       
   547         command.setSubIndex(command_infos["Subindex"])
       
   548         command.setData(command_infos["Value"])
       
   549         command.setComment(command_infos["Description"])
       
   550         InitCmds.appendInitCmd(command)
       
   551         return len(InitCmds.getInitCmd()) - 1
       
   552     setattr(cls, "appendStartupCommand", appendStartupCommand)
       
   553     
       
   554     def setStartupCommand(self, command_infos):
       
   555         InitCmds = self.getInitCmds()
       
   556         if InitCmds is not None:
       
   557             commands = InitCmds.getInitCmd()
       
   558             if command_infos["command_idx"] < len(commands):
       
   559                 command = commands[command_infos["command_idx"]]
       
   560                 command.setIndex(command_infos["Index"])
       
   561                 command.setSubIndex(command_infos["Subindex"])
       
   562                 command.setData(command_infos["Value"])
       
   563                 command.setComment(command_infos["Description"])
       
   564     setattr(cls, "setStartupCommand", setStartupCommand)
       
   565     
       
   566     def removeStartupCommand(self, command_idx):
       
   567         InitCmds = self.getInitCmds()
       
   568         if InitCmds is not None:
       
   569             if command_idx < len(InitCmds.getInitCmd()):
       
   570                 InitCmds.removeInitCmd(command_idx)
       
   571     setattr(cls, "removeStartupCommand", removeStartupCommand)
       
   572 
       
   573 ProcessVariablesXSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   494     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   574     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   495       <xsd:element name="EtherlabNode">
   575       <xsd:element name="ProcessVariables">
   496         <xsd:complexType>
   576         <xsd:complexType>
   497           <xsd:attribute name="MasterNumber" type="xsd:integer" use="optional" default="0"/>
   577           <xsd:sequence>
       
   578             <xsd:element name="variable" minOccurs="0" maxOccurs="unbounded">
       
   579               <xsd:complexType>
       
   580                 <xsd:sequence>
       
   581                   <xsd:element name="ReadFrom" type="LocationDesc" minOccurs="0"/>
       
   582                   <xsd:element name="WriteTo" type="LocationDesc" minOccurs="0"/>
       
   583                 </xsd:sequence>
       
   584                 <xsd:attribute name="Name" type="xsd:string" use="required"/>
       
   585                 <xsd:attribute name="Comment" type="xsd:string" use="required"/>
       
   586               </xsd:complexType>
       
   587             </xsd:element>
       
   588           </xsd:sequence>
   498         </xsd:complexType>
   589         </xsd:complexType>
   499       </xsd:element>
   590       </xsd:element>
       
   591       <xsd:complexType name="LocationDesc">
       
   592         <xsd:attribute name="Position" type="xsd:integer" use="required"/>
       
   593         <xsd:attribute name="Index" type="xsd:integer" use="required"/>
       
   594         <xsd:attribute name="SubIndex" type="xsd:integer" use="required"/>
       
   595       </xsd:complexType>
   500     </xsd:schema>
   596     </xsd:schema>
   501     """
   597 """
       
   598 
       
   599 ProcessVariablesClasses = GenerateClassesFromXSDstring(ProcessVariablesXSD) 
       
   600 
       
   601 class _EthercatCTN:
   502     
   602     
   503     CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")]
   603     CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")]
   504     if HAS_MCL:
   604     if HAS_MCL:
   505         CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave"))
   605         CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave"))
       
   606     EditorType = MasterEditor
   506     
   607     
   507     def __init__(self):
   608     def __init__(self):
   508         filepath = self.ConfigFileName()
   609         config_filepath = self.ConfigFileName()
   509         
   610         config_is_saved = False
   510         self.Config = EtherCATConfigClasses["EtherCATConfig"]()
   611         self.Config = EtherCATConfigClasses["EtherCATConfig"]()
   511         if os.path.isfile(filepath):
   612         if os.path.isfile(config_filepath):
   512             xmlfile = open(filepath, 'r')
   613             config_xmlfile = open(config_filepath, 'r')
   513             tree = minidom.parse(xmlfile)
   614             config_tree = minidom.parse(config_xmlfile)
   514             xmlfile.close()
   615             config_xmlfile.close()
   515             
   616             
   516             for child in tree.childNodes:
   617             for child in config_tree.childNodes:
   517                 if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "EtherCATConfig":
   618                 if child.nodeType == config_tree.ELEMENT_NODE and child.nodeName == "EtherCATConfig":
   518                     self.Config.loadXMLTree(child)
   619                     self.Config.loadXMLTree(child)
   519                     self.CreateConfigBuffer(True)
   620                     config_is_saved = True
       
   621         
       
   622         process_filepath = self.ProcessVariablesFileName()
       
   623         process_is_saved = False
       
   624         self.ProcessVariables = ProcessVariablesClasses["ProcessVariables"]()
       
   625         if os.path.isfile(process_filepath):
       
   626             process_xmlfile = open(process_filepath, 'r')
       
   627             process_tree = minidom.parse(process_xmlfile)
       
   628             process_xmlfile.close()
       
   629             
       
   630             for child in process_tree.childNodes:
       
   631                 if child.nodeType == process_tree.ELEMENT_NODE and child.nodeName == "ProcessVariables":
       
   632                     self.ProcessVariables.loadXMLTree(child)
       
   633                     process_is_saved = True
       
   634         
       
   635         if config_is_saved and process_is_saved:
       
   636             self.CreateBuffer(True)
   520         else:
   637         else:
   521             self.CreateConfigBuffer(False)
   638             self.CreateBuffer(False)
   522             self.OnCTNSave()
   639             self.OnCTNSave()
   523 
   640 
   524     def ExtractHexDecValue(self, value):
   641     def ExtractHexDecValue(self, value):
   525         return ExtractHexDecValue(value)
   642         return ExtractHexDecValue(value)
   526 
   643 
   527     def GetSizeOfType(self, type):
   644     def GetSizeOfType(self, type):
   528         return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None)
   645         return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None)
   529 
   646 
   530     def ConfigFileName(self):
   647     def ConfigFileName(self):
   531         return os.path.join(self.CTNPath(), "config.xml")
   648         return os.path.join(self.CTNPath(), "config.xml")
   532 
   649     
       
   650     def ProcessVariablesFileName(self):
       
   651         return os.path.join(self.CTNPath(), "process_variables.xml")
       
   652     
   533     def GetSlaves(self):
   653     def GetSlaves(self):
   534         slaves = []
   654         slaves = []
   535         for slave in self.Config.getConfig().getSlave():
   655         for slave in self.Config.getConfig().getSlave():
   536             slaves.append(slave.getInfo().getPhysAddr())
   656             slaves.append(slave.getInfo().getPhysAddr())
   537         slaves.sort()
   657         slaves.sort()
   542             slave_info = slave.getInfo()
   662             slave_info = slave.getInfo()
   543             if slave_info.getPhysAddr() == slave_pos:
   663             if slave_info.getPhysAddr() == slave_pos:
   544                 return slave
   664                 return slave
   545         return None
   665         return None
   546 
   666 
       
   667     def FilterSlave(self, slave, vendor=None, slave_pos=None, slave_profile=None):
       
   668         if slave_pos is not None and slave.getInfo().getPhysAddr() != slave_pos:
       
   669             return False
       
   670         type_infos = slave.getType()
       
   671         if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor:
       
   672             return False
       
   673         device, alignment = self.GetModuleInfos(type_infos)
       
   674         if slave_profile is not None and slave_profile not in device.GetProfileNumbers():
       
   675             return False
       
   676         return True
       
   677 
       
   678     def GetStartupCommands(self, vendor=None, slave_pos=None, slave_profile=None):
       
   679         commands = []
       
   680         for slave in self.Config.getConfig().getSlave():
       
   681             if self.FilterSlave(slave, vendor, slave_pos, slave_profile):
       
   682                 commands.append((slave.getInfo().getPhysAddr(), slave.getStartupCommands()))
       
   683         commands.sort()
       
   684         return reduce(lambda x, y: x + y[1], commands, [])
       
   685     
       
   686     def AppendStartupCommand(self, command_infos):
       
   687         slave = self.GetSlave(command_infos["Position"])
       
   688         if slave is not None:
       
   689             command_idx = slave.appendStartupCommand(command_infos)
       
   690             self.BufferModel()
       
   691             return command_idx
       
   692         return None
       
   693     
       
   694     def SetStartupCommandInfos(self, command_infos):
       
   695         slave = self.GetSlave(command_infos["Position"])
       
   696         if slave is not None:
       
   697             slave.setStartupCommand(command_infos)
       
   698             self.BufferModel()
       
   699     
       
   700     def RemoveStartupCommand(self, slave_pos, command_idx):
       
   701         slave = self.GetSlave(slave_pos)
       
   702         if slave is not None:
       
   703             slave.removeStartupCommand(command_idx)
       
   704             self.BufferModel()
       
   705     
       
   706     def SetProcessVariables(self, variables):
       
   707         vars = []
       
   708         for var in variables:
       
   709             variable = ProcessVariablesClasses["ProcessVariables_variable"]()
       
   710             variable.setName(var["Name"])
       
   711             variable.setComment(var["Description"])
       
   712             if var["ReadFrom"] != "":
       
   713                 position, index, subindex = var["ReadFrom"]
       
   714                 if variable.getReadFrom() is None:
       
   715                     variable.addReadFrom()
       
   716                 read_from = variable.getReadFrom()
       
   717                 read_from.setPosition(position)
       
   718                 read_from.setIndex(index)
       
   719                 read_from.setSubIndex(subindex)
       
   720             elif variable.getReadFrom() is not None:
       
   721                 variable.deleteReadFrom()
       
   722             if var["WriteTo"] != "":
       
   723                 position, index, subindex = var["WriteTo"]
       
   724                 if variable.getWriteTo() is None:
       
   725                     variable.addWriteTo()
       
   726                 write_to = variable.getWriteTo()
       
   727                 write_to.setPosition(position)
       
   728                 write_to.setIndex(index)
       
   729                 write_to.setSubIndex(subindex)
       
   730             elif variable.getWriteTo() is not None:
       
   731                 variable.deleteWriteTo()
       
   732             vars.append(variable)
       
   733         self.ProcessVariables.setvariable(vars)
       
   734         self.BufferModel()
       
   735         
       
   736     def GetProcessVariables(self):
       
   737         variables = []
       
   738         for variable in self.ProcessVariables.getvariable():
       
   739             var = {"Name": variable.getName(),
       
   740                    "Description": variable.getComment()}
       
   741             read_from = variable.getReadFrom()
       
   742             if read_from is not None:
       
   743                 var["ReadFrom"] = (read_from.getPosition(),
       
   744                                    read_from.getIndex(),
       
   745                                    read_from.getSubIndex())
       
   746             else:
       
   747                 var["ReadFrom"] = ""
       
   748             write_to = variable.getWriteTo()
       
   749             if write_to is not None:
       
   750                 var["WriteTo"] = (write_to.getPosition(),
       
   751                                    write_to.getIndex(),
       
   752                                    write_to.getSubIndex())
       
   753             else:
       
   754                 var["WriteTo"] = ""
       
   755             variables.append(var)
       
   756         return variables
       
   757     
   547     def _ScanNetwork(self):
   758     def _ScanNetwork(self):
   548         app_frame = self.GetCTRoot().AppFrame
   759         app_frame = self.GetCTRoot().AppFrame
   549         
   760         
   550         execute = True
   761         execute = True
   551         if len(self.Children) > 0:
   762         if len(self.Children) > 0:
   597             slave_infos = slave.getInfo()
   808             slave_infos = slave.getInfo()
   598             slave_infos.setName("undefined")
   809             slave_infos.setName("undefined")
   599             slave_infos.setPhysAddr(newConfNodeOpj.BaseParams.getIEC_Channel())
   810             slave_infos.setPhysAddr(newConfNodeOpj.BaseParams.getIEC_Channel())
   600             slave_infos.setAutoIncAddr(0)
   811             slave_infos.setAutoIncAddr(0)
   601             self.Config.getConfig().appendSlave(slave)
   812             self.Config.getConfig().appendSlave(slave)
   602             self.BufferConfig()
   813             self.BufferModel()
   603             self.OnCTNSave()
   814             self.OnCTNSave()
   604         
   815         
   605         return newConfNodeOpj
   816         return newConfNodeOpj
   606 
   817 
   607     def _doRemoveChild(self, CTNInstance):
   818     def _doRemoveChild(self, CTNInstance):
   609         config = self.Config.getConfig()
   820         config = self.Config.getConfig()
   610         for idx, slave in enumerate(config.getSlave()):
   821         for idx, slave in enumerate(config.getSlave()):
   611             slave_infos = slave.getInfo()
   822             slave_infos = slave.getInfo()
   612             if slave_infos.getPhysAddr() == slave_pos:
   823             if slave_infos.getPhysAddr() == slave_pos:
   613                 config.removeSlave(idx)
   824                 config.removeSlave(idx)
   614                 self.BufferConfig()
   825                 self.BufferModel()
   615                 self.OnCTNSave()
   826                 self.OnCTNSave()
   616         ConfigTreeNode._doRemoveChild(self, CTNInstance)
   827         ConfigTreeNode._doRemoveChild(self, CTNInstance)
   617 
   828 
   618     def SetSlavePosition(self, slave_pos, new_pos):
   829     def SetSlavePosition(self, slave_pos, new_pos):
   619         slave = self.GetSlave(slave_pos)
   830         slave = self.GetSlave(slave_pos)
   620         if slave is not None:
   831         if slave is not None:
   621             slave_info = slave.getInfo()
   832             slave_info = slave.getInfo()
   622             slave_info.setPhysAddr(new_pos)
   833             slave_info.setPhysAddr(new_pos)
   623             self.BufferConfig()
   834             self.BufferModel()
   624     
   835     
   625     def GetSlaveAlias(self, slave_pos):
   836     def GetSlaveAlias(self, slave_pos):
   626         slave = self.GetSlave(slave_pos)
   837         slave = self.GetSlave(slave_pos)
   627         if slave is not None:
   838         if slave is not None:
   628             slave_info = slave.getInfo()
   839             slave_info = slave.getInfo()
   632     def SetSlaveAlias(self, slave_pos, alias):
   843     def SetSlaveAlias(self, slave_pos, alias):
   633         slave = self.GetSlave(slave_pos)
   844         slave = self.GetSlave(slave_pos)
   634         if slave is not None:
   845         if slave is not None:
   635             slave_info = slave.getInfo()
   846             slave_info = slave.getInfo()
   636             slave_info.setAutoIncAddr(alias)
   847             slave_info.setAutoIncAddr(alias)
   637             self.BufferConfig()
   848             self.BufferModel()
   638     
   849     
   639     def GetSlaveType(self, slave_pos):
   850     def GetSlaveType(self, slave_pos):
   640         slave = self.GetSlave(slave_pos)
   851         slave = self.GetSlave(slave_pos)
   641         if slave is not None:
   852         if slave is not None:
   642             return slave.getType()
   853             return slave.getType()
   644     
   855     
   645     def SetSlaveType(self, slave_pos, type_infos):
   856     def SetSlaveType(self, slave_pos, type_infos):
   646         slave = self.GetSlave(slave_pos)
   857         slave = self.GetSlave(slave_pos)
   647         if slave is not None:
   858         if slave is not None:
   648             slave.setType(type_infos)
   859             slave.setType(type_infos)
   649             self.BufferConfig()
   860             self.BufferModel()
   650     
   861     
   651     def GetSlaveInfos(self, slave_pos):
   862     def GetSlaveInfos(self, slave_pos):
   652         slave = self.GetSlave(slave_pos)
   863         slave = self.GetSlave(slave_pos)
   653         if slave is not None:
   864         if slave is not None:
   654             type_infos = slave.getType()
   865             type_infos = slave.getType()
   655             device, alignement = self.GetModuleInfos(type_infos)
   866             device, alignment = self.GetModuleInfos(type_infos)
   656             if device is not None:
   867             if device is not None:
   657                 infos = type_infos.copy()
   868                 infos = type_infos.copy()
   658                 entries = device.GetEntriesList()
       
   659                 entries_list = entries.items()
       
   660                 entries_list.sort()
       
   661                 entries = []
       
   662                 current_index = None
       
   663                 current_entry = None
       
   664                 for (index, subindex), entry in entries_list:
       
   665                     entry["children"] = []
       
   666                     if index != current_index:
       
   667                         current_index = index
       
   668                         current_entry = entry
       
   669                         entries.append(entry)
       
   670                     elif current_entry is not None:
       
   671                         current_entry["children"].append(entry)
       
   672                     else:
       
   673                         entries.append(entry)
       
   674                 infos.update({"physics": device.getPhysics(),
   869                 infos.update({"physics": device.getPhysics(),
   675                               "sync_managers": device.GetSyncManagers(),
   870                               "sync_managers": device.GetSyncManagers(),
   676                               "entries": entries})
   871                               "entries": self.GetSlaveVariables(device)})
   677                 return infos
   872                 return infos
   678         return None
   873         return None
   679     
   874     
       
   875     def GetSlaveVariables(self, slave_pos=None, limits=None, device=None):
       
   876         if device is None and slave_pos is not None:
       
   877             slave = self.GetSlave(slave_pos)
       
   878             if slave is not None:
       
   879                 type_infos = slave.getType()
       
   880                 device, alignment = self.GetModuleInfos(type_infos)
       
   881         if device is not None:
       
   882             entries = device.GetEntriesList(limits)
       
   883             entries_list = entries.items()
       
   884             entries_list.sort()
       
   885             entries = []
       
   886             current_index = None
       
   887             current_entry = None
       
   888             for (index, subindex), entry in entries_list:
       
   889                 entry["children"] = []
       
   890                 if slave_pos is not None:
       
   891                     entry["Position"] = str(slave_pos)
       
   892                 entry
       
   893                 if index != current_index:
       
   894                     current_index = index
       
   895                     current_entry = entry
       
   896                     entries.append(entry)
       
   897                 elif current_entry is not None:
       
   898                     current_entry["children"].append(entry)
       
   899                 else:
       
   900                     entries.append(entry)
       
   901             return entries
       
   902         return []
       
   903     
       
   904     def GetNodesVariables(self, vendor=None, slave_pos=None, slave_profile=None, limits=None):
       
   905         entries = []
       
   906         for slave_position in self.GetSlaves():
       
   907             if slave_pos is not None and slave_position != slave_pos:
       
   908                 continue
       
   909             slave = self.GetSlave(slave_position)
       
   910             type_infos = slave.getType()
       
   911             if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor:
       
   912                 continue
       
   913             device, alignment = self.GetModuleInfos(type_infos)
       
   914             if slave_profile is not None and slave_profile not in device.GetProfileNumbers():
       
   915                 continue
       
   916             entries.extend(self.GetSlaveVariables(slave_position, limits, device))
       
   917         return entries
       
   918      
   680     def GetModuleInfos(self, type_infos):
   919     def GetModuleInfos(self, type_infos):
   681         return self.CTNParent.GetModuleInfos(type_infos)
   920         return self.CTNParent.GetModuleInfos(type_infos)
   682     
   921     
   683     def GetSlaveTypesLibrary(self, profile_filter=None):
   922     def GetSlaveTypesLibrary(self, profile_filter=None):
   684         return self.CTNParent.GetModulesLibrary(profile_filter)
   923         return self.CTNParent.GetModulesLibrary(profile_filter)
       
   924     
       
   925     def GetLibraryVendors(self):
       
   926         return self.CTNParent.GetVendors()
   685     
   927     
   686     def GetDeviceLocationTree(self, slave_pos, current_location, device_name):
   928     def GetDeviceLocationTree(self, slave_pos, current_location, device_name):
   687         slave = self.GetSlave(slave_pos)
   929         slave = self.GetSlave(slave_pos)
   688         vars = []    
   930         vars = []    
   689         if slave is not None:
   931         if slave is not None:
   690             type_infos = slave.getType()
   932             type_infos = slave.getType()
   691         
   933         
   692             device, alignement = self.GetModuleInfos(type_infos)
   934             device, alignment = self.GetModuleInfos(type_infos)
   693             if device is not None:
   935             if device is not None:
   694                 sync_managers = []
   936                 sync_managers = []
   695                 for sync_manager in device.getSm():
   937                 for sync_manager in device.getSm():
   696                     sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
   938                     sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
   697                     sync_manager_direction = sync_manager_control_byte & 0x0c
   939                     sync_manager_direction = sync_manager_control_byte & 0x0c
   723                                          "children": []})
   965                                          "children": []})
   724         
   966         
   725         return vars
   967         return vars
   726     
   968     
   727     def CTNTestModified(self):
   969     def CTNTestModified(self):
   728         return self.ChangesToSave or not self.ConfigIsSaved()    
   970         return self.ChangesToSave or not self.ModelIsSaved()    
   729 
   971 
   730     def OnCTNSave(self):
   972     def OnCTNSave(self):
   731         filepath = self.ConfigFileName()
   973         config_filepath = self.ConfigFileName()
   732         
   974         
   733         text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
   975         config_text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
   734         extras = {"xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
   976         config_extras = {"xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
   735                   "xsi:noNamespaceSchemaLocation" : "EtherCATInfo.xsd"}
   977                   "xsi:noNamespaceSchemaLocation" : "EtherCATInfo.xsd"}
   736         text += self.Config.generateXMLText("EtherCATConfig", 0, extras)
   978         config_text += self.Config.generateXMLText("EtherCATConfig", 0, config_extras)
   737 
   979 
   738         xmlfile = open(filepath,"w")
   980         config_xmlfile = open(config_filepath,"w")
   739         xmlfile.write(text.encode("utf-8"))
   981         config_xmlfile.write(config_text.encode("utf-8"))
   740         xmlfile.close()
   982         config_xmlfile.close()
   741         
   983         
   742         self.ConfigBuffer.CurrentSaved()
   984         process_filepath = self.ProcessVariablesFileName()
       
   985         
       
   986         process_text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
       
   987         process_extras = {"xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance"}
       
   988         process_text += self.ProcessVariables.generateXMLText("ProcessVariables", 0, process_extras)
       
   989 
       
   990         process_xmlfile = open(process_filepath,"w")
       
   991         process_xmlfile.write(process_text.encode("utf-8"))
       
   992         process_xmlfile.close()
       
   993         
       
   994         self.Buffer.CurrentSaved()
   743         return True
   995         return True
   744 
   996 
   745     def _Generate_C(self, buildpath, locations):
   997     def _Generate_C(self, buildpath, locations):
   746         current_location = self.GetCurrentLocation()
   998         current_location = self.GetCurrentLocation()
   747         # define a unique name for the generated C file
   999         # define a unique name for the generated C file
   808     Return a copy of the config
  1060     Return a copy of the config
   809     """
  1061     """
   810     def Copy(self, model):
  1062     def Copy(self, model):
   811         return cPickle.loads(cPickle.dumps(model))
  1063         return cPickle.loads(cPickle.dumps(model))
   812     
  1064     
   813     def CreateConfigBuffer(self, saved):
  1065     def CreateBuffer(self, saved):
   814         self.ConfigBuffer = UndoBuffer(cPickle.dumps(self.Config), saved)
  1066         self.Buffer = UndoBuffer(cPickle.dumps((self.Config, self.ProcessVariables)), saved)
   815         
  1067         
   816     def BufferConfig(self):
  1068     def BufferModel(self):
   817         self.ConfigBuffer.Buffering(cPickle.dumps(self.Config))
  1069         self.Buffer.Buffering(cPickle.dumps((self.Config, self.ProcessVariables)))
   818     
  1070     
   819     def ConfigIsSaved(self):
  1071     def ModelIsSaved(self):
   820         if self.ConfigBuffer is not None:
  1072         if self.Buffer is not None:
   821             return self.ConfigBuffer.IsCurrentSaved()
  1073             return self.Buffer.IsCurrentSaved()
   822         else:
  1074         else:
   823             return True
  1075             return True
   824 
  1076 
   825     def LoadPrevious(self):
  1077     def LoadPrevious(self):
   826         self.Config = cPickle.loads(self.ConfigBuffer.Previous())
  1078         self.Config, self.ProcessVariables = cPickle.loads(self.Buffer.Previous())
   827     
  1079     
   828     def LoadNext(self):
  1080     def LoadNext(self):
   829         self.Config = cPickle.loads(self.ConfigBuffer.Next())
  1081         self.Config, self.ProcessVariables = cPickle.loads(self.Buffer.Next())
   830     
  1082     
   831     def GetBufferState(self):
  1083     def GetBufferState(self):
   832         first = self.ConfigBuffer.IsFirst()
  1084         first = self.Buffer.IsFirst()
   833         last = self.ConfigBuffer.IsLast()
  1085         last = self.Buffer.IsLast()
   834         return not first, not last
  1086         return not first, not last
   835 
  1087 
   836 
  1088 
   837 SLAVE_PDOS_CONFIGURATION_DECLARATION = """
  1089 SLAVE_PDOS_CONFIGURATION_DECLARATION = """
   838 /* Slave %(slave)d, "%(device_type)s"
  1090 /* Slave %(slave)d, "%(device_type)s"
   981         plc_etherlab_file.close()
  1233         plc_etherlab_file.close()
   982         
  1234         
   983         # Initialize strings for formatting master code template
  1235         # Initialize strings for formatting master code template
   984         str_completion = {
  1236         str_completion = {
   985             "location": location_str,
  1237             "location": location_str,
   986             "master_number": etherlab_node_infos.getMasterNumber(),
  1238             "master_number": self.BaseParams.getIEC_Channel(),
   987             "located_variables_declaration": [],
  1239             "located_variables_declaration": [],
   988             "used_pdo_entry_offset_variables_declaration": [],
  1240             "used_pdo_entry_offset_variables_declaration": [],
   989             "used_pdo_entry_configuration": [],
  1241             "used_pdo_entry_configuration": [],
   990             "pdos_configuration_declaration": "",
  1242             "pdos_configuration_declaration": "",
   991             "slaves_declaration": "",
  1243             "slaves_declaration": "",
  1015             else:
  1267             else:
  1016                 alias[slave_alias] = 0
  1268                 alias[slave_alias] = 0
  1017             slave_pos = (slave_alias, alias[slave_alias])
  1269             slave_pos = (slave_alias, alias[slave_alias])
  1018             
  1270             
  1019             # Extract slave device informations
  1271             # Extract slave device informations
  1020             device, alignement = self.Controler.GetModuleInfos(type_infos)
  1272             device, alignment = self.Controler.GetModuleInfos(type_infos)
  1021             if device is not None:
  1273             if device is not None:
  1022                 
  1274                 
  1023                 # Extract slaves variables to be mapped
  1275                 # Extract slaves variables to be mapped
  1024                 slave_variables = self.UsedVariables.get(slave_idx, {})
  1276                 slave_variables = self.UsedVariables.get(slave_idx, {})
  1025                 
  1277                 
  1411     
  1663     
  1412     def ExtractDataTypes(self):
  1664     def ExtractDataTypes(self):
  1413         self.DataTypes = {}
  1665         self.DataTypes = {}
  1414         
  1666         
  1415         for dictionary in self.GetProfileDictionaries():
  1667         for dictionary in self.GetProfileDictionaries():
       
  1668             dictionary.load()
  1416             
  1669             
  1417             datatypes = dictionary.getDataTypes()
  1670             datatypes = dictionary.getDataTypes()
  1418             if datatypes is not None:
  1671             if datatypes is not None:
  1419                 
  1672                 
  1420                 for datatype in datatypes.getDataType():
  1673                 for datatype in datatypes.getDataType():
  1429         if mailbox is not None:
  1682         if mailbox is not None:
  1430             return mailbox.getCoE()
  1683             return mailbox.getCoE()
  1431         return None
  1684         return None
  1432     setattr(cls, "getCoE", getCoE)
  1685     setattr(cls, "getCoE", getCoE)
  1433 
  1686 
  1434     def GetEntriesList(self):
  1687     def GetEntriesList(self, limits=None):
  1435         if self.DataTypes is None:
  1688         if self.DataTypes is None:
  1436             self.ExtractDataTypes()
  1689             self.ExtractDataTypes()
  1437         
  1690         
  1438         entries = {}
  1691         entries = {}
  1439         
  1692         
  1441             dictionary.load()
  1694             dictionary.load()
  1442             
  1695             
  1443             for object in dictionary.getObjects().getObject():
  1696             for object in dictionary.getObjects().getObject():
  1444                 entry_index = object.getIndex().getcontent()
  1697                 entry_index = object.getIndex().getcontent()
  1445                 index = ExtractHexDecValue(entry_index)
  1698                 index = ExtractHexDecValue(entry_index)
  1446                 entry_type = object.getType()
  1699                 if limits is None or limits[0] <= index <= limits[1]:
  1447                 entry_name = ExtractName(object.getName())
  1700                     entry_type = object.getType()
  1448                 
  1701                     entry_name = ExtractName(object.getName())
  1449                 entry_type_infos = self.DataTypes.get(entry_type, None)
  1702                     
  1450                 if entry_type_infos is not None:
  1703                     entry_type_infos = self.DataTypes.get(entry_type, None)
  1451                     content = entry_type_infos.getcontent()
  1704                     if entry_type_infos is not None:
  1452                     for subitem in content["value"]:
  1705                         content = entry_type_infos.getcontent()
  1453                         entry_subidx = subitem.getSubIdx()
  1706                         for subitem in content["value"]:
  1454                         if entry_subidx is None:
  1707                             entry_subidx = subitem.getSubIdx()
  1455                             entry_subidx = "0"
  1708                             if entry_subidx is None:
  1456                         subidx = ExtractHexDecValue(entry_subidx)
  1709                                 entry_subidx = "0"
  1457                         subitem_access = ""
  1710                             subidx = ExtractHexDecValue(entry_subidx)
  1458                         subitem_pdomapping = ""
  1711                             subitem_access = ""
  1459                         subitem_flags = subitem.getFlags()
  1712                             subitem_pdomapping = ""
  1460                         if subitem_flags is not None:
  1713                             subitem_flags = subitem.getFlags()
  1461                             access = subitem_flags.getAccess()
  1714                             if subitem_flags is not None:
       
  1715                                 access = subitem_flags.getAccess()
       
  1716                                 if access is not None:
       
  1717                                     subitem_access = access.getcontent()
       
  1718                                 pdomapping = subitem_flags.getPdoMapping()
       
  1719                                 if pdomapping is not None:
       
  1720                                     subitem_pdomapping = pdomapping.upper()
       
  1721                             entries[(index, subidx)] = {
       
  1722                                 "Index": entry_index,
       
  1723                                 "SubIndex": entry_subidx,
       
  1724                                 "Name": "%s - %s" % 
       
  1725                                         (entry_name.decode("utf-8"),
       
  1726                                          ExtractName(subitem.getDisplayName(), 
       
  1727                                                      subitem.getName()).decode("utf-8")),
       
  1728                                 "Type": subitem.getType(),
       
  1729                                 "BitSize": subitem.getBitSize(),
       
  1730                                 "Access": subitem_access, 
       
  1731                                 "PDOMapping": subitem_pdomapping}
       
  1732                     else:
       
  1733                         entry_access = ""
       
  1734                         entry_pdomapping = ""
       
  1735                         entry_flags = object.getFlags()
       
  1736                         if entry_flags is not None:
       
  1737                             access = entry_flags.getAccess()
  1462                             if access is not None:
  1738                             if access is not None:
  1463                                 subitem_access = access.getcontent()
  1739                                 entry_access = access.getcontent()
  1464                             pdomapping = subitem_flags.getPdoMapping()
  1740                             pdomapping = entry_flags.getPdoMapping()
  1465                             if pdomapping is not None:
  1741                             if pdomapping is not None:
  1466                                 subitem_pdomapping = pdomapping.upper()
  1742                                 entry_pdomapping = pdomapping.upper()
  1467                         entries[(index, subidx)] = {
  1743                         entries[(index, 0)] = {
  1468                             "Index": entry_index,
  1744                              "Index": entry_index,
  1469                             "SubIndex": entry_subidx,
  1745                              "SubIndex": "0",
  1470                             "Name": "%s - %s" % 
  1746                              "Name": entry_name,
  1471                                     (entry_name.decode("utf-8"),
  1747                              "Type": entry_type,
  1472                                      ExtractName(subitem.getDisplayName(), 
  1748                              "BitSize": object.getBitSize(),
  1473                                                  subitem.getName()).decode("utf-8")),
  1749                              "Access": entry_access,
  1474                             "Type": subitem.getType(),
  1750                              "PDOMapping": entry_pdomapping}
  1475                             "BitSize": subitem.getBitSize(),
       
  1476                             "Access": subitem_access, 
       
  1477                             "PDOMapping": subitem_pdomapping}
       
  1478                 else:
       
  1479                     entry_access = ""
       
  1480                     entry_pdomapping = ""
       
  1481                     entry_flags = object.getFlags()
       
  1482                     if entry_flags is not None:
       
  1483                         access = entry_flags.getAccess()
       
  1484                         if access is not None:
       
  1485                             entry_access = access.getcontent()
       
  1486                         pdomapping = entry_flags.getPdoMapping()
       
  1487                         if pdomapping is not None:
       
  1488                             entry_pdomapping = pdomapping.upper()
       
  1489                     entries[(index, 0)] = {
       
  1490                          "Index": entry_index,
       
  1491                          "SubIndex": "0",
       
  1492                          "Name": entry_name,
       
  1493                          "Type": entry_type,
       
  1494                          "BitSize": object.getBitSize(),
       
  1495                          "Access": entry_access,
       
  1496                          "PDOMapping": entry_pdomapping}
       
  1497         
  1751         
  1498         for TxPdo in self.getTxPdo():
  1752         for TxPdo in self.getTxPdo():
  1499             ExtractPdoInfos(TxPdo, "Transmit", entries)
  1753             ExtractPdoInfos(TxPdo, "Transmit", entries, limits)
  1500         for RxPdo in self.getRxPdo():
  1754         for RxPdo in self.getRxPdo():
  1501             ExtractPdoInfos(RxPdo, "Receive", entries)
  1755             ExtractPdoInfos(RxPdo, "Receive", entries, limits)
  1502         
  1756         
  1503         return entries
  1757         return entries
  1504     setattr(cls, "GetEntriesList", GetEntriesList)
  1758     setattr(cls, "GetEntriesList", GetEntriesList)
  1505 
  1759 
  1506     def GetSyncManagers(self):
  1760     def GetSyncManagers(self):
  1542         for name in names:
  1796         for name in names:
  1543             if name.getLcId() == 1033:
  1797             if name.getLcId() == 1033:
  1544                 return name.getcontent()
  1798                 return name.getcontent()
  1545     return default
  1799     return default
  1546 
  1800 
  1547 def ExtractPdoInfos(pdo, pdo_type, entries):
  1801 def ExtractPdoInfos(pdo, pdo_type, entries, limits=None):
  1548     pdo_index = pdo.getIndex().getcontent()
  1802     pdo_index = pdo.getIndex().getcontent()
  1549     pdo_name = ExtractName(pdo.getName())
  1803     pdo_name = ExtractName(pdo.getName())
  1550     for pdo_entry in pdo.getEntry():
  1804     for pdo_entry in pdo.getEntry():
  1551         entry_index = pdo_entry.getIndex().getcontent()
  1805         entry_index = pdo_entry.getIndex().getcontent()
  1552         entry_subindex = pdo_entry.getSubIndex()
  1806         entry_subindex = pdo_entry.getSubIndex()
  1553         index = ExtractHexDecValue(entry_index)
  1807         index = ExtractHexDecValue(entry_index)
  1554         subindex = ExtractHexDecValue(entry_subindex)
  1808         subindex = ExtractHexDecValue(entry_subindex)
  1555         
  1809         
  1556         entry = entries.get((index, subindex), None)
  1810         if limits is None or limits[0] <= index <= limits[1]:
  1557         if entry is not None:
  1811             entry = entries.get((index, subindex), None)
  1558             entry["PDO index"] = pdo_index
  1812             if entry is not None:
  1559             entry["PDO name"] = pdo_name
  1813                 entry["PDO index"] = pdo_index
  1560             entry["PDO type"] = pdo_type
  1814                 entry["PDO name"] = pdo_name
  1561         else:
  1815                 entry["PDO type"] = pdo_type
  1562             entry_type = pdo_entry.getDataType()
  1816             else:
  1563             if entry_type is not None:
  1817                 entry_type = pdo_entry.getDataType()
  1564                 if pdo_type == "Transmit":
  1818                 if entry_type is not None:
  1565                     access = "ro"
  1819                     if pdo_type == "Transmit":
  1566                     pdomapping = "T"
  1820                         access = "ro"
  1567                 else:
  1821                         pdomapping = "T"
  1568                     access = "wo"
  1822                     else:
  1569                     pdomapping = "R"
  1823                         access = "wo"
  1570                 entries[(index, subindex)] = {
  1824                         pdomapping = "R"
  1571                     "Index": entry_index,
  1825                     entries[(index, subindex)] = {
  1572                     "SubIndex": entry_subindex,
  1826                         "Index": entry_index,
  1573                     "Name": ExtractName(pdo_entry.getName()),
  1827                         "SubIndex": entry_subindex,
  1574                     "Type": entry_type.getcontent(),
  1828                         "Name": ExtractName(pdo_entry.getName()),
  1575                     "Access": access,
  1829                         "Type": entry_type.getcontent(),
  1576                     "PDOMapping": pdomapping}
  1830                         "Access": access,
       
  1831                         "PDOMapping": pdomapping}
  1577 
  1832 
  1578 DEFAULT_ALIGNMENT = 8
  1833 DEFAULT_ALIGNMENT = 8
  1579 
  1834 
  1580 class ModulesLibrary:
  1835 class ModulesLibrary:
  1581     
  1836     
  1583         self.Path = path
  1838         self.Path = path
  1584         if not os.path.exists(self.Path):
  1839         if not os.path.exists(self.Path):
  1585             os.makedirs(self.Path)
  1840             os.makedirs(self.Path)
  1586         self.ParentLibrary = parent_library
  1841         self.ParentLibrary = parent_library
  1587         
  1842         
  1588         self.LoadModules()
  1843         if parent_library is not None:
       
  1844             self.LoadModules()
       
  1845         else:
       
  1846             self.Library = None
  1589         self.LoadAlignments()
  1847         self.LoadAlignments()
  1590     
  1848     
  1591     def GetPath(self):
  1849     def GetPath(self):
  1592         return self.Path
  1850         return self.Path
  1593     
  1851     
  1631                         if not vendor_category["groups"].has_key(device_group):
  1889                         if not vendor_category["groups"].has_key(device_group):
  1632                             raise ValueError, "Not such group \"%\"" % device_group
  1890                             raise ValueError, "Not such group \"%\"" % device_group
  1633                         vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device))
  1891                         vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device))
  1634 
  1892 
  1635     def GetModulesLibrary(self, profile_filter=None):
  1893     def GetModulesLibrary(self, profile_filter=None):
       
  1894         if self.Library is None:
       
  1895             self.LoadModules()
  1636         library = []
  1896         library = []
  1637         for vendor_id, vendor in self.Library.iteritems():
  1897         for vendor_id, vendor in self.Library.iteritems():
  1638             groups = []
  1898             groups = []
  1639             children_dict = {}
  1899             children_dict = {}
  1640             for group_type, group in vendor["groups"].iteritems():
  1900             for group_type, group in vendor["groups"].iteritems():
  1676                                 "infos": None,
  1936                                 "infos": None,
  1677                                 "children": groups})
  1937                                 "children": groups})
  1678         library.sort(lambda x, y: cmp(x["name"], y["name"]))
  1938         library.sort(lambda x, y: cmp(x["name"], y["name"]))
  1679         return library
  1939         return library
  1680 
  1940 
       
  1941     def GetVendors(self):
       
  1942         return [(vendor_id, vendor["name"]) for vendor_id, vendor in self.Library.items()]
       
  1943     
  1681     def GetModuleInfos(self, module_infos):
  1944     def GetModuleInfos(self, module_infos):
  1682         vendor = ExtractHexDecValue(module_infos["vendor"])
  1945         vendor = ExtractHexDecValue(module_infos["vendor"])
  1683         vendor_infos = self.Library.get(vendor)
  1946         vendor_infos = self.Library.get(vendor)
  1684         if vendor_infos is not None:
  1947         if vendor_infos is not None:
  1685             for group_name, group_infos in vendor_infos["groups"].iteritems():
  1948             for group_name, group_infos in vendor_infos["groups"].iteritems():
  1783         return self.ModulesLibrary
  2046         return self.ModulesLibrary
  1784     
  2047     
  1785     def GetModulesLibrary(self, profile_filter=None):
  2048     def GetModulesLibrary(self, profile_filter=None):
  1786         return self.ModulesLibrary.GetModulesLibrary(profile_filter)
  2049         return self.ModulesLibrary.GetModulesLibrary(profile_filter)
  1787     
  2050     
       
  2051     def GetVendors(self):
       
  2052         return self.ModulesLibrary.GetVendors()
       
  2053     
  1788     def GetModuleInfos(self, module_infos):
  2054     def GetModuleInfos(self, module_infos):
  1789         return self.ModulesLibrary.GetModuleInfos(module_infos)
  2055         return self.ModulesLibrary.GetModuleInfos(module_infos)
  1790 
  2056 
  1791             
  2057