etherlab/EthercatMaster.py
branchethercat_from_kosmos
changeset 2641 c9deff128c37
parent 2165 02a2b5dee5e3
child 2643 b98d9e08231f
equal deleted inserted replaced
2192:09d5d1456616 2641:c9deff128c37
    83         Gen_etherlabfile_path = os.path.join(buildpath, "etherlab_ext.c")
    83         Gen_etherlabfile_path = os.path.join(buildpath, "etherlab_ext.c")
    84         ethelabfile = open(Gen_etherlabfile_path,'w')
    84         ethelabfile = open(Gen_etherlabfile_path,'w')
    85         ethelabfile.write(etherlab_ext_code)
    85         ethelabfile.write(etherlab_ext_code)
    86         ethelabfile.close()
    86         ethelabfile.close()
    87         
    87         
    88         runtimefile_path = os.path.join(os.path.split(__file__)[0], "runtime_etherlab.py")
    88         try:
    89         return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", 
    89             return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", 
    90                 ("runtime_etherlab.py", file(GetLocalPath("runtime_etherlab.py"))))
    90                 ("runtime_etherlab.py", file(GetLocalPath("runtime_etherlab.py"))))
       
    91         except:
       
    92             return ((["etherlab_ext"], [(Gen_etherlabfile_path, IECCFLAGS)], True), "", 
       
    93                 ("runtime_etherlab.pyc", file(GetLocalPath("runtime_etherlab.pyc"))))
    91     
    94     
    92 #--------------------------------------------------
    95 #--------------------------------------------------
    93 #                 Ethercat MASTER
    96 #                 Ethercat MASTER
    94 #--------------------------------------------------
    97 #--------------------------------------------------
    95 
    98 
   219 """
   222 """
   220 
   223 
   221 ProcessVariablesParser = GenerateParserFromXSDstring(ProcessVariablesXSD) 
   224 ProcessVariablesParser = GenerateParserFromXSDstring(ProcessVariablesXSD) 
   222 
   225 
   223 class _EthercatCTN:
   226 class _EthercatCTN:
   224 
   227     
   225     CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")]
   228     CTNChildrenTypes = [("EthercatSlave", _EthercatSlaveCTN, "Ethercat Slave")]
   226     if HAS_MCL:
   229     if HAS_MCL:
   227         CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave"))
   230         CTNChildrenTypes.append(("EthercatCIA402Slave", _EthercatCIA402SlaveCTN, "Ethercat CIA402 Slave"))
   228     EditorType = MasterEditor
   231     EditorType = MasterEditor
   229     
   232     
   230     def __init__(self):
   233     def __init__(self):
   231         config_filepath = self.ConfigFileName()
   234         config_filepath = self.ConfigFileName()
   232         config_is_saved = False
   235         config_is_saved = False
   233         self.Config = None
   236         self.Config = None
   234         if os.path.isfile(config_filepath):
   237 
   235             config_xmlfile = open(config_filepath, 'r')
   238         #if os.path.isfile(config_filepath):
   236             try:
   239         #    config_xmlfile = open(config_filepath, 'r')
   237                 self.Config, error = \
   240         #    try:
   238                     EtherCATConfigParser.LoadXMLString(config_xmlfile.read())
   241         #        self.Config, error = \
   239                 if error is None:
   242         #            EtherCATConfigParser.LoadXMLString(config_xmlfile.read())
   240                     config_is_saved = True
   243         #        if error is None:
   241             except Exception, e:
   244         #            config_is_saved = True
   242                 error = e.message
   245         #    except Exception, e:
   243             config_xmlfile.close()
   246         #        error = e.message
       
   247         #    config_xmlfile.close()
   244             
   248             
   245             if error is not None:
   249         #    if error is not None:
   246                 self.GetCTRoot().logger.write_error(
   250         #        self.GetCTRoot().logger.write_error(
   247                     _("Couldn't load %s network configuration file.") % CTNName)    
   251         #            _("Couldn't load %s network configuration file.") % CTNName)    
   248             
   252             
   249         if self.Config is None:
   253         if self.Config is None:
   250             self.Config = EtherCATConfigParser.CreateElement("EtherCATConfig")
   254             self.Config = EtherCATConfigParser.CreateElement("EtherCATConfig")
   251         
   255         
   252         process_filepath = self.ProcessVariablesFileName()
   256         process_filepath = self.ProcessVariablesFileName()
   268                     _("Couldn't load %s network process variables file.") % CTNName)    
   272                     _("Couldn't load %s network process variables file.") % CTNName)    
   269             
   273             
   270         if self.ProcessVariables is None:
   274         if self.ProcessVariables is None:
   271             self.ProcessVariables = ProcessVariablesParser.CreateElement("ProcessVariables")
   275             self.ProcessVariables = ProcessVariablesParser.CreateElement("ProcessVariables")
   272         
   276         
   273         if config_is_saved and process_is_saved:
   277         #if config_is_saved and process_is_saved:
       
   278         if process_is_saved:
   274             self.CreateBuffer(True)
   279             self.CreateBuffer(True)
   275         else:
   280         else:
   276             self.CreateBuffer(False)
   281             self.CreateBuffer(False)
   277             self.OnCTNSave()
   282             self.OnCTNSave()
   278          
   283 
       
   284         if os.path.isfile(config_filepath):
       
   285             config_xmlfile = open(config_filepath, 'r')
       
   286             try:
       
   287                 self.Config, error = \
       
   288                     EtherCATConfigParser.LoadXMLString(config_xmlfile.read())
       
   289                 if error is None:
       
   290                     config_is_saved = True
       
   291             except Exception, e:
       
   292                 error = e.message
       
   293             config_xmlfile.close()
       
   294             
       
   295             if error is not None:
       
   296                 self.GetCTRoot().logger.write_error(
       
   297                     _("Couldn't load %s network configuration file.") % CTNName)
       
   298 
   279         # ----------- call ethercat mng. function --------------
   299         # ----------- call ethercat mng. function --------------
   280         self.CommonMethod = _CommonSlave(self)
   300         self.CommonMethod = _CommonSlave(self)
       
   301         
       
   302         ###################################### Test Section #########################################
   281     
   303     
   282     def GetIconName(self):
   304     def GetIconName(self):
   283         return "Ethercat"
   305         return "Ethercat"
   284     
   306     
   285     def GetContextualMenuItems(self):
   307     def GetContextualMenuItems(self):
   291             "Ethercat Slave Type", self.GetSlaveTypesLibrary())
   313             "Ethercat Slave Type", self.GetSlaveTypesLibrary())
   292         if dialog.ShowModal() == wx.ID_OK:
   314         if dialog.ShowModal() == wx.ID_OK:
   293             type_infos = dialog.GetValueInfos()
   315             type_infos = dialog.GetValueInfos()
   294             device, module_extra_params = self.GetModuleInfos(type_infos)
   316             device, module_extra_params = self.GetModuleInfos(type_infos)
   295             if device is not None:
   317             if device is not None:
   296                 if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers():
   318                 # device.GetProfileNumbers() return type is string
       
   319                 # _EthercatCIA402SlaveCTN.NODE_PROFILE change to string
       
   320                 # 151224 jblee
       
   321                 if HAS_MCL and str(_EthercatCIA402SlaveCTN.NODE_PROFILE) in device.GetProfileNumbers():
   297                     ConfNodeType = "EthercatCIA402Slave"
   322                     ConfNodeType = "EthercatCIA402Slave"
   298                 else:
   323                 else:
   299                     ConfNodeType = "EthercatSlave"
   324                     ConfNodeType = "EthercatSlave"
   300                 new_child = self.CTNAddChild("%s_0" % ConfNodeType, ConfNodeType)
   325                 new_child = self.CTNAddChild("%s_0" % ConfNodeType, ConfNodeType)
   301                 new_child.SetParamsAttribute("SlaveParams.Type", type_infos)
   326                 new_child.SetParamsAttribute("SlaveParams.Type", type_infos)
   561                               "sync_managers": device.GetSyncManagers(),
   586                               "sync_managers": device.GetSyncManagers(),
   562                               "entries": self.GetSlaveVariables(device)})
   587                               "entries": self.GetSlaveVariables(device)})
   563                 return infos
   588                 return infos
   564         return None
   589         return None
   565     
   590     
       
   591     """
   566     def GetSlaveVariables(self, slave_pos=None, limits=None, device=None):
   592     def GetSlaveVariables(self, slave_pos=None, limits=None, device=None):
   567         if device is None and slave_pos is not None:
   593         if device is None and slave_pos is not None:
   568             slave = self.GetSlave(slave_pos)
   594             slave = self.GetSlave(slave_pos)
   569             if slave is not None:
   595             if slave is not None:
   570                 type_infos = slave.getType()
   596                 type_infos = slave.getType()
   571                 device, module_extra_params = self.GetModuleInfos(type_infos)
   597                 device, module_extra_params = self.GetModuleInfos(type_infos)
   572         if device is not None:
   598         if device is not None:
   573             entries = device.GetEntriesList(limits)
   599             entries = device.GetEntriesList(limits)
   574             #print entries
       
   575             entries_list = entries.items()
   600             entries_list = entries.items()
   576             entries_list.sort()
   601             entries_list.sort()
   577             entries = []
   602             entries = []
   578             current_index = None
   603             current_index = None
   579             current_entry = None
   604             current_entry = None
   590                     current_entry["children"].append(entry)
   615                     current_entry["children"].append(entry)
   591                 else:
   616                 else:
   592                     entries.append(entry)
   617                     entries.append(entry)
   593             return entries
   618             return entries
   594         return []
   619         return []
       
   620     #"""
       
   621 
       
   622     def GetSlaveVariables(self, slave_pos=None, limits=None, device=None, module=None):
       
   623         # add jblee
       
   624         files = os.listdir(self.CTNPath())
       
   625         moduleNames = []
       
   626         modulePos = 1
       
   627         for file in files:
       
   628             filepath = os.path.join(self.CTNPath(), file)
       
   629             if os.path.isdir(filepath):
       
   630                 MDPFilePath = os.path.join(filepath, "DataForMDP.txt")
       
   631                 CheckConfNodePath = os.path.join(filepath, "baseconfnode.xml")
       
   632 
       
   633                 try :
       
   634                     moduleDataFile = open(MDPFilePath, 'r')
       
   635                     confNodeFile = open(CheckConfNodePath, 'r')
       
   636 
       
   637                     lines = moduleDataFile.readlines()
       
   638                     checklines = confNodeFile.readlines()
       
   639 
       
   640                     moduleDataFile.close()
       
   641                     confNodeFile.close()
       
   642 
       
   643                     module_info = self.GetModuleEntryList()
       
   644                     # checklines(ex) : <BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="EthercatSlave_0"/>
       
   645                     # checklines[1].split() : [<BaseParams, xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       
   646                     #                           IEC_Channel="0", Name="EthercatSlave_0"/>]
       
   647                     # checklines[1].split()[2] : IEC_Channel="0"
       
   648                     # checklines[1].split()[2].split("\"") = [IEC_Channel=, 0, ]
       
   649                     pos_check = int(checklines[1].split()[2].split("\"")[1])
       
   650 
       
   651                     if slave_pos != pos_check:
       
   652                         continue
       
   653 
       
   654                     for line in lines:
       
   655                         if line == "\n":
       
   656                             continue
       
   657                         # module_name : ST-1214, ST-2314, ...
       
   658                         # if user add module => ST-1214 3EA, ST-2314 3EA
       
   659                         # each result_module_name : 
       
   660                         #    (ST-1214, Module 1), (ST-1214, Module 2), (ST-1214, Module 3)
       
   661                         #    (ST-2314, Module 4), (ST-2314, Module 5), (ST-2314, Module 6)  
       
   662                         module_name = line.split()[0]
       
   663                         result_module_name = module_name + ", Module %d" % modulePos
       
   664                         moduleNames.append(result_module_name)
       
   665                         modulePos += 1
       
   666                 except :
       
   667                     pass
       
   668 
       
   669         if device is None and slave_pos is not None:
       
   670             slave = self.GetSlave(slave_pos)
       
   671             if slave is not None:
       
   672                 type_infos = slave.getType()
       
   673                 device, module_extra_params = self.GetModuleInfos(type_infos)
       
   674                 
       
   675         if device is not None:
       
   676             # Test OD
       
   677             entries = device.GetEntriesList(limits)
       
   678             #entries = self.CTNParent.GetEntriesList()
       
   679             entries_list = entries.items()
       
   680             entries_list.sort()
       
   681             entries = []
       
   682             current_index = None
       
   683             current_entry = None
       
   684             for (index, subindex), entry in entries_list:
       
   685                 entry["children"] = []
       
   686                 if slave_pos is not None:
       
   687                     entry["Position"] = str(slave_pos)
       
   688                 entry
       
   689                 if index != current_index:
       
   690                     current_index = index
       
   691                     current_entry = entry
       
   692                     entries.append(entry)
       
   693                 elif current_entry is not None:
       
   694                     current_entry["children"].append(entry)
       
   695                 else:
       
   696                     entries.append(entry)
       
   697 
       
   698             increment = self.CTNParent.GetModuleIncrement()[0]
       
   699             count = 1
       
   700             #print module_info
       
   701             # moduleNameAndPos : (ST-1214, Module 1), (ST-1214, Module 2), ... ,
       
   702             # moduleNameAndPos.split(",") : ["ST-1214", " Module 1"]
       
   703             # moduleNameAndPos.split(",")[0] : "ST-1214"
       
   704             for moduleNameAndPos in moduleNames:
       
   705                 moduleName = moduleNameAndPos.split(",")[0]
       
   706                 modulePosName = moduleNameAndPos.split(",")[1]
       
   707                 idx_increment = int(increment) * count
       
   708                 
       
   709                 for MDP_entry in module_info.get(moduleName):
       
   710                     LocalMDPEntry = []
       
   711                     #print MDP_entry
       
   712                     local_idx = MDP_entry["Index"]
       
   713                     if ExtractHexDecValue(local_idx) == 0: #and local_idx[0] == "#":
       
   714                         temp_index = ExtractHexDecValue(local_idx)
       
   715                     else :
       
   716                         temp_index = ExtractHexDecValue(MDP_entry["Index"]) + idx_increment
       
   717                     #temp_index = ExtractHexDecValue(MDP_entry["Index"]) + idx_increment
       
   718                     entry_index = hex(temp_index)
       
   719                     entry_subidx = MDP_entry["SubIndex"]
       
   720                     entry_name = MDP_entry["Name"] + ", " + " " + \
       
   721                                  moduleName + " - " + modulePosName
       
   722                     entry_type = MDP_entry["Type"]
       
   723                     entry_bitsize = MDP_entry["BitSize"]
       
   724                     entry_access = MDP_entry["Access"]
       
   725                     mapping_type = MDP_entry["PDOMapping"]
       
   726 
       
   727                     LocalMDPEntry.append({
       
   728                         "Index": entry_index,
       
   729                         "SubIndex": entry_subidx,
       
   730                         "Name": entry_name,
       
   731                         "Type": entry_type,
       
   732                         "BitSize": entry_bitsize,
       
   733                         "Access": entry_access, 
       
   734                         "PDOMapping": mapping_type,
       
   735                         "children": ""})
       
   736                     entries.append(LocalMDPEntry[0])
       
   737                 count += 1
       
   738             
       
   739             #print entries
       
   740             return entries
       
   741         return []
   595     
   742     
   596     def GetSlaveVariableDataType(self, slave_pos, index, subindex):
   743     def GetSlaveVariableDataType(self, slave_pos, index, subindex):
   597         slave = self.GetSlave(slave_pos)
   744         slave = self.GetSlave(slave_pos)
   598         if slave is not None:
   745         if slave is not None:
   599             device, module_extra_params = self.GetModuleInfos(slave.getType())
   746             device, module_extra_params = self.GetModuleInfos(slave.getType())
   600             if device is not None:
   747             if device is not None:
   601                 entries = device.GetEntriesList()
   748                 entries = device.GetEntriesList()
       
   749                 #entries = self.CTNParent.GetEntriesList()
   602                 entry_infos = entries.get((index, subindex))
   750                 entry_infos = entries.get((index, subindex))
   603                 if entry_infos is not None:
   751                 if entry_infos is not None:
   604                     return entry_infos["Type"]
   752                     return entry_infos["Type"]
   605         return None
   753         return None
   606     
   754     
   619             entries.extend(self.GetSlaveVariables(slave_position, limits, device))
   767             entries.extend(self.GetSlaveVariables(slave_position, limits, device))
   620         return entries
   768         return entries
   621      
   769      
   622     def GetModuleInfos(self, type_infos):
   770     def GetModuleInfos(self, type_infos):
   623         return self.CTNParent.GetModuleInfos(type_infos)
   771         return self.CTNParent.GetModuleInfos(type_infos)
       
   772 
       
   773     # add jblee
       
   774     def GetModuleEntryList(self):
       
   775         return self.CTNParent.GetModuleEntryList()
   624     
   776     
   625     def GetSlaveTypesLibrary(self, profile_filter=None):
   777     def GetSlaveTypesLibrary(self, profile_filter=None):
   626         return self.CTNParent.GetModulesLibrary(profile_filter)
   778         return self.CTNParent.GetModulesLibrary(profile_filter)
   627     
   779     
   628     def GetLibraryVendors(self):
   780     def GetLibraryVendors(self):
   629         return self.CTNParent.GetVendors()
   781         return self.CTNParent.GetVendors()
   630     
   782     
   631     def GetDeviceLocationTree(self, slave_pos, current_location, device_name):
   783     def GetDeviceLocationTree(self, slave_pos, current_location, device_name):
   632         slave = self.GetSlave(slave_pos)
   784         slave = self.GetSlave(slave_pos)
   633         vars = []    
   785         vars = []
       
   786 
       
   787         # add jblee
       
   788         files = os.listdir(self.CTNPath())
       
   789         moduleNames = []
       
   790         modulePos = 1
       
   791         for file in files:
       
   792             filepath = os.path.join(self.CTNPath(), file)
       
   793             if os.path.isdir(filepath):
       
   794                 MDPFilePath = os.path.join(filepath, "DataForMDP.txt")
       
   795                 CheckConfNodePath = os.path.join(filepath, "baseconfnode.xml")
       
   796 
       
   797                 try :
       
   798                     moduleDataFile = open(MDPFilePath, 'r')
       
   799                     confNodeFile = open(CheckConfNodePath, 'r')
       
   800 
       
   801                     lines = moduleDataFile.readlines()
       
   802                     checklines = confNodeFile.readlines()
       
   803 
       
   804                     moduleDataFile.close()
       
   805                     confNodeFile.close()
       
   806 
       
   807                     module_info = self.GetModuleEntryList()
       
   808                     # checklines(ex) : <BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="EthercatSlave_0"/>
       
   809                     # checklines[1].split() : [<BaseParams, xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       
   810                     #                           IEC_Channel="0", Name="EthercatSlave_0"/>]
       
   811                     # checklines[1].split()[2] : IEC_Channel="0"
       
   812                     # checklines[1].split()[2].split("\"") = [IEC_Channel=, 0, ]
       
   813                     pos_check = int(checklines[1].split()[2].split("\"")[1])
       
   814 
       
   815                     if slave_pos != pos_check:
       
   816                         continue
       
   817 
       
   818                     for line in lines:
       
   819                         if line == "\n":
       
   820                             continue
       
   821                         # module_name : ST-1214, ST-2314, ...
       
   822                         # if user add module => ST-1214 3EA, ST-2314 3EA
       
   823                         # each result_module_name : 
       
   824                         #    (ST-1214, Module 1), (ST-1214, Module 2), (ST-1214, Module 3)
       
   825                         #    (ST-2314, Module 4), (ST-2314, Module 5), (ST-2314, Module 6)  
       
   826                         module_name = line.split()[0]
       
   827                         result_module_name = module_name + ", Module %d" % modulePos
       
   828                         moduleNames.append(result_module_name)
       
   829                         modulePos += 1
       
   830                 except :
       
   831                     pass
       
   832 
   634         if slave is not None:
   833         if slave is not None:
   635             type_infos = slave.getType()
   834             type_infos = slave.getType()
   636         
   835         
   637             device, module_extra_params = self.GetModuleInfos(type_infos)
   836             device, module_extra_params = self.GetModuleInfos(type_infos)
   638             if device is not None:
   837             if device is not None:
   643                     if sync_manager_direction:
   842                     if sync_manager_direction:
   644                         sync_managers.append(LOCATION_VAR_OUTPUT)
   843                         sync_managers.append(LOCATION_VAR_OUTPUT)
   645                     else:
   844                     else:
   646                         sync_managers.append(LOCATION_VAR_INPUT)
   845                         sync_managers.append(LOCATION_VAR_INPUT)
   647                 
   846                 
       
   847                 # Test OD
   648                 entries = device.GetEntriesList().items()
   848                 entries = device.GetEntriesList().items()
       
   849                 #entries = self.CTNParent.GetEntriesList().items()
   649                 entries.sort()
   850                 entries.sort()
       
   851                 
   650                 for (index, subindex), entry in entries:
   852                 for (index, subindex), entry in entries:
   651                     var_size = self.GetSizeOfType(entry["Type"])
   853                     var_size = self.GetSizeOfType(entry["Type"])
   652                     if var_size is not None:
   854                     if var_size is not None:
   653                         var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None)
   855                         var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None)
   654                         if var_class is not None:
   856                         if var_class is not None:
   664                                          "var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex),
   866                                          "var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex),
   665                                          "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
   867                                          "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
   666                                                                                                     (index, subindex)))),
   868                                                                                                     (index, subindex)))),
   667                                          "description": "",
   869                                          "description": "",
   668                                          "children": []})
   870                                          "children": []})
   669         
   871 
       
   872                 # add jblee for MDP
       
   873                 if not entries :
       
   874                     increment = self.CTNParent.GetModuleIncrement()[0]
       
   875                     count = 1
       
   876                     for moduleNameAndPos in moduleNames:
       
   877                         moduleName = moduleNameAndPos.split(",")[0]
       
   878                         idx_increment = int(increment) * count
       
   879                         for MDP_entry in module_info.get(moduleName):
       
   880                             local_idx = MDP_entry["Index"]
       
   881                             if ExtractHexDecValue(local_idx) != 0 and local_idx[0] == "#":
       
   882                                 index = ExtractHexDecValue(local_idx) + idx_increment
       
   883                             else :
       
   884                                 index = ExtractHexDecValue(MDP_entry["Index"])
       
   885                             subindex = int(MDP_entry["SubIndex"])
       
   886                             var_class = VARCLASSCONVERSION.get(MDP_entry["PDOMapping"], None)
       
   887                             if var_class is not None:
       
   888                                 if var_class == LOCATION_VAR_INPUT:
       
   889                                     var_dir = "%I"
       
   890                                 else:
       
   891                                     var_dir = "%Q"
       
   892                             var_size = self.GetSizeOfType(MDP_entry["Type"])
       
   893                             result_name = MDP_entry["Name"] + ", " + moduleNameAndPos
       
   894                             vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, result_name),
       
   895                                          "type": var_class,
       
   896                                          "size": var_size,
       
   897                                          "IEC_type": MDP_entry["Type"],
       
   898                                          "var_name": "%s_%4.4x_%2.2x" % ("_".join(moduleName.split()), index, subindex),
       
   899                                          "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
       
   900                                                                                                     (index, subindex)))),
       
   901                                          "description": "",
       
   902                                          "children": []})
       
   903                         count += 1
       
   904 
   670         return vars
   905         return vars
   671     
   906     
   672     def CTNTestModified(self):
   907     def CTNTestModified(self):
   673         return self.ChangesToSave or not self.ModelIsSaved()    
   908         return self.ChangesToSave or not self.ModelIsSaved()    
   674 
   909 
   675     def OnCTNSave(self, from_project_path=None):
   910     def OnCTNSave(self, from_project_path=None):
   676         config_filepath = self.ConfigFileName()
   911         config_filepath = self.ConfigFileName()
   677         
       
   678         config_xmlfile = open(config_filepath,"w")
   912         config_xmlfile = open(config_filepath,"w")
   679         config_xmlfile.write(etree.tostring(
   913         config_xmlfile.write(etree.tostring(
   680             self.Config, 
   914             self.Config, 
   681             pretty_print=True, 
   915             pretty_print=True, 
   682             xml_declaration=True, 
   916             xml_declaration=True,