allow writing of diseqc tester results to /media/hdd/diseqctester.log
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / DiseqcTester / plugin.py
1 from Screens.Satconfig import NimSelection
2 from Screens.Screen import Screen
3 from Screens.TextBox import TextBox
4 from Screens.MessageBox import MessageBox
5
6 from Plugins.Plugin import PluginDescriptor
7
8 from Components.ActionMap import ActionMap, NumberActionMap
9 from Components.NimManager import nimmanager
10 from Components.ResourceManager import resourcemanager
11 from Components.Sources.FrontendStatus import FrontendStatus
12 from Components.TuneTest import TuneTest
13 from Components.Sources.List import List
14 from Components.Sources.Progress import Progress
15 from Components.Sources.StaticText import StaticText
16 from Components.ConfigList import ConfigListScreen
17 from Components.config import getConfigListEntry, ConfigSelection, ConfigYesNo
18 from Components.Harddisk import harddiskmanager
19
20 import random
21
22 # always use:
23 # setResultType(type)
24 # setResultParameter(parameter)
25 # getTextualResult()
26 class ResultParser:
27         def __init__(self):
28                 pass
29         
30         TYPE_BYORBPOS = 0
31         TYPE_BYINDEX = 1
32         TYPE_ALL = 2
33         def setResultType(self, type):
34                 self.type = type
35                 
36         def setResultParameter(self, parameter):
37                 if self.type == self.TYPE_BYORBPOS:
38                         self.orbpos = parameter
39                 elif self.type == self.TYPE_BYINDEX:
40                         self.index = parameter
41                         
42         def getTextualResultForIndex(self, index, logfulltransponders = False):
43                 text = ""
44                 text += "%s:\n" % self.getTextualIndexRepresentation(index)
45                 
46                 failed, successful = self.results[index]["failed"], self.results[index]["successful"]
47                 countfailed = len(failed)
48                 countsuccessful = len(successful)
49                 countall = countfailed + countsuccessful
50                 percentfailed = round(countfailed / float(countall + 0.0001) * 100)
51                 percentsuccessful = round(countsuccessful / float(countall + 0.0001) * 100)
52                 text += "Tested %d transponders\n%d (%d %%) transponders succeeded\n%d (%d %%) transponders failed\n" % (countall, countsuccessful, percentsuccessful, countfailed, percentfailed)
53                 reasons = {}
54                 if countfailed > 0:
55                         for transponder in failed:
56                                 reasons[transponder[2]] = reasons.get(transponder[2], [])
57                                 reasons[transponder[2]].append(transponder)
58                                 if transponder[2] == "pids_failed":
59                                         print transponder[2], "-", transponder[3]
60                                 
61                         text += "The %d unsuccessful tuning attempts failed for the following reasons:\n" % countfailed
62                         
63                         for reason in reasons.keys():
64                                 text += "%s: %d transponders failed\n" % (reason, len(reasons[reason]))
65                         
66                         for reason in reasons.keys():
67                                 text += "\n"
68                                 text += "%s previous planes:\n" % reason
69                                 for transponder in reasons[reason]:
70                                         if transponder[1] is not None:
71                                                 text += self.getTextualIndexRepresentation(self.getIndexForTransponder(transponder[1]))
72                                         else:
73                                                 text += "No transponder tuned"
74                                         text += " ==> " + self.getTextualIndexRepresentation(self.getIndexForTransponder(transponder[0]))
75                                         text += "\n"
76                                         if logfulltransponders:
77                                                 text += str(transponder[1])
78                                                 text += " ==> "
79                                                 text += str(transponder[0])
80                                                 text += "\n"
81                 if countsuccessful > 0:
82                         text += "\n"
83                         text += "Successfully tuned transponders' previous planes:\n" 
84                         for transponder in successful:
85                                 if transponder[1] is not None:
86                                         text += self.getTextualIndexRepresentation(self.getIndexForTransponder(transponder[1]))
87                                 else:
88                                         text += "No transponder tuned"
89                                 text += " ==> " + self.getTextualIndexRepresentation(self.getIndexForTransponder(transponder[0]))
90                                 text += "\n"
91                 return text
92
93         def getTextualResult(self):
94                 text = ""
95                 if self.type == self.TYPE_BYINDEX:
96                         text += self.getTextualResultForIndex(self.index)
97                 elif self.type == self.TYPE_BYORBPOS:
98                         for index in self.results.keys():
99                                 if index[2] == self.orbpos:
100                                         text += self.getTextualResultForIndex(index)
101                                         text += "\n-----------------------------------------------------\n"
102                 elif self.type == self.TYPE_ALL:
103                         orderedResults = {}
104                         for index in self.results.keys():
105                                 orbpos = index[2]
106                                 orderedResults[orbpos] = orderedResults.get(orbpos, [])
107                                 orderedResults[orbpos].append(index)
108                         ordered_orbpos = orderedResults.keys()
109                         ordered_orbpos.sort()
110                         for orbpos in ordered_orbpos:
111                                 text += "\n*****************************************\n"
112                                 text += "Orbital position %s:" % str(orbpos)
113                                 text += "\n*****************************************\n"
114                                 for index in orderedResults[orbpos]:
115                                         text += self.getTextualResultForIndex(index, logfulltransponders = True)
116                                         text += "\n-----------------------------------------------------\n"
117                         
118                                 
119                 return text
120
121 class DiseqcTester(Screen, TuneTest, ResultParser):
122         skin = """
123                 <screen position="90,100" size="520,400" title="DiSEqC Tester" >
124                 <!--ePixmap pixmap="skin_default/icons/dish_scan.png" position="5,25" zPosition="0" size="119,110" transparent="1" alphatest="on" />
125                 <widget source="Frontend" render="Label" position="190,10" zPosition="2" size="260,20" font="Regular;19" halign="center" valign="center" transparent="1">
126                         <convert type="FrontendInfo">SNRdB</convert>
127                 </widget>
128                 <eLabel name="snr" text="SNR:" position="120,35" size="60,22" font="Regular;21" halign="right" transparent="1" />
129                 <widget source="Frontend" render="Progress" position="190,35" size="260,20" pixmap="skin_default/bar_snr.png" borderWidth="2" borderColor="#cccccc">
130                         <convert type="FrontendInfo">SNR</convert>
131                 </widget>
132                 <widget source="Frontend" render="Label" position="460,35" size="60,22" font="Regular;21">
133                         <convert type="FrontendInfo">SNR</convert>
134                 </widget>
135                 <eLabel name="agc" text="AGC:" position="120,60" size="60,22" font="Regular;21" halign="right" transparent="1" />
136                 <widget source="Frontend" render="Progress" position="190,60" size="260,20" pixmap="skin_default/bar_snr.png" borderWidth="2" borderColor="#cccccc">
137                         <convert type="FrontendInfo">AGC</convert>
138                 </widget>
139                 <widget source="Frontend" render="Label" position="460,60" size="60,22" font="Regular;21">
140                         <convert type="FrontendInfo">AGC</convert>
141                 </widget>
142                 <eLabel name="ber" text="BER:" position="120,85" size="60,22" font="Regular;21" halign="right" transparent="1" />
143                 <widget source="Frontend" render="Progress" position="190,85" size="260,20" pixmap="skin_default/bar_ber.png" borderWidth="2" borderColor="#cccccc">
144                         <convert type="FrontendInfo">BER</convert>
145                 </widget>
146                 <widget source="Frontend" render="Label" position="460,85" size="60,22" font="Regular;21">
147                         <convert type="FrontendInfo">BER</convert>
148                 </widget>
149                 <eLabel name="lock" text="Lock:" position="120,115" size="60,22" font="Regular;21" halign="right" />
150                 <widget source="Frontend" render="Pixmap" pixmap="skin_default/icons/lock_on.png" position="190,110" zPosition="1" size="38,31" alphatest="on">
151                         <convert type="FrontendInfo">LOCK</convert>
152                         <convert type="ConditionalShowHide" />
153                 </widget>
154                 <widget source="Frontend" render="Pixmap" pixmap="skin_default/icons/lock_off.png" position="190,110" zPosition="1" size="38,31" alphatest="on">
155                         <convert type="FrontendInfo">LOCK</convert>
156                         <convert type="ConditionalShowHide">Invert</convert>
157                 </widget-->
158                 <widget source="progress_list" render="Listbox" position="0,0" size="510,150" scrollbarMode="showOnDemand">
159                         <convert type="TemplatedMultiContent">
160                                 {"template": [
161                                                 MultiContentEntryText(pos = (10, 0), size = (330, 25), flags = RT_HALIGN_LEFT, text = 1), # index 1 is the index name,
162                                                 MultiContentEntryText(pos = (330, 0), size = (150, 25), flags = RT_HALIGN_RIGHT, text = 2) # index 2 is the status,
163                                         ],
164                                  "fonts": [gFont("Regular", 20)],
165                                  "itemHeight": 25
166                                 }
167                         </convert>
168                 </widget>
169                 <eLabel name="overall_progress" text="Overall progress:" position="20,162" size="480,22" font="Regular;21" halign="center" transparent="1" />
170                 <widget source="overall_progress" render="Progress" position="20,192" size="480,20" borderWidth="2" backgroundColor="#254f7497" />
171                 <eLabel name="overall_progress" text="Progress:" position="20,222" size="480,22" font="Regular;21" halign="center" transparent="1" />
172                 <widget source="sub_progress" render="Progress" position="20,252" size="480,20" borderWidth="2" backgroundColor="#254f7497" />
173                 
174                 <eLabel name="" text="Failed:" position="20,282" size="140,22" font="Regular;21" halign="left" transparent="1" />
175                 <widget source="failed_counter" render="Label" position="160,282" size="100,20" font="Regular;21" />
176                 
177                 <eLabel name="" text="Succeeded:" position="20,312" size="140,22" font="Regular;21" halign="left" transparent="1" />
178                 <widget source="succeeded_counter" render="Label" position="160,312" size="100,20" font="Regular;21" />
179                 
180                 <eLabel name="" text="With errors:" position="20,342" size="140,22" font="Regular;21" halign="left" transparent="1" />
181                 <widget source="witherrors_counter" render="Label" position="160,342" size="100,20" font="Regular;21" />
182                 
183                 <eLabel name="" text="Not tested:" position="20,372" size="140,22" font="Regular;21" halign="left" transparent="1" />
184                 <widget source="untestable_counter" render="Label" position="160,372" size="100,20" font="Regular;21" />
185                 
186                 <widget source="CmdText" render="Label" position="300,282" size="180,200" font="Regular;21" />
187                 </screen>"""
188                 
189         TEST_TYPE_QUICK = 0
190         TEST_TYPE_RANDOM = 1
191         TEST_TYPE_COMPLETE = 2
192         def __init__(self, session, feid, test_type = TEST_TYPE_QUICK, loopsfailed = 3, loopssuccessful = 1, log = False):
193                 Screen.__init__(self, session)
194                 self.feid = feid
195                 self.test_type = test_type
196                 self.loopsfailed = loopsfailed
197                 self.loopssuccessful = loopssuccessful
198                 self.log = log
199                 
200                 self["actions"] = NumberActionMap(["SetupActions"],
201                 {
202                         "ok": self.select,
203                         "cancel": self.keyCancel,
204                 }, -2)
205                 
206                 TuneTest.__init__(self, feid, stopOnSuccess = self.loopssuccessful, stopOnError = self.loopsfailed)
207                 #self["Frontend"] = FrontendStatus(frontend_source = lambda : self.frontend, update_interval = 100)
208                 self["overall_progress"] = Progress()
209                 self["sub_progress"] = Progress()
210                 
211                 self["failed_counter"] = StaticText("0")
212                 self["succeeded_counter"] = StaticText("0")
213                 self["witherrors_counter"] = StaticText("0")
214                 self["untestable_counter"] = StaticText("0")
215                 
216                 self.list = []
217                 self["progress_list"] = List(self.list)
218                 self["progress_list"].onSelectionChanged.append(self.selectionChanged)
219                 
220                 self["CmdText"] = StaticText(_("Please wait while scanning is in progress..."))
221                                 
222                 self.indexlist = {}
223                 self.readTransponderList()
224                 
225                 self.running = False
226                 
227                 self.results = {}
228                 self.resultsstatus = {}
229                 
230                 self.onLayoutFinish.append(self.go)
231                 
232         def getProgressListComponent(self, index, status):
233                 return (index, self.getTextualIndexRepresentation(index), status)
234         
235         def clearProgressList(self):
236                 self.list = []
237                 self["progress_list"].list = self.list
238         
239         def addProgressListItem(self, index):
240                 if index in self.indexlist:
241                         for entry in self.list:
242                                 if entry[0] == index:
243                                         self.changeProgressListStatus(index, "working")
244                                         return
245                         self.list.append(self.getProgressListComponent(index, _("working")))
246                         self["progress_list"].list = self.list
247                         self["progress_list"].setIndex(len(self.list) - 1)
248
249         def changeProgressListStatus(self, index, status):
250                 self.newlist = []
251                 count = 0
252                 indexpos = 0
253                 for entry in self.list:
254                         if entry[0] == index:
255                                 self.newlist.append(self.getProgressListComponent(index, status))
256                                 indexpos = count
257                         else:
258                                 self.newlist.append(entry)
259                         count += 1
260                 self.list = self.newlist
261                 self["progress_list"].list = self.list
262                 self["progress_list"].setIndex(indexpos)
263
264         def readTransponderList(self):
265                 for sat in nimmanager.getSatListForNim(self.feid):
266                         for transponder in nimmanager.getTransponders(sat[0]):
267                                 #print transponder
268                                 mytransponder = (transponder[1] / 1000, transponder[2] / 1000, transponder[3], transponder[4], transponder[5], sat[0], None, None, transponder[10], transponder[11])
269                                 self.analyseTransponder(mytransponder)
270
271         def getIndexForTransponder(self, transponder):
272                 
273                 if transponder[0] < 11700:
274                         band = 1 # low
275                 else:
276                         band = 0 # high
277                 
278                 polarisation = transponder[2]
279                 
280                 sat = transponder[5]
281                 
282                 index = (band, polarisation, sat)
283                 return index
284
285         # sort the transponder into self.transponderlist
286         def analyseTransponder(self, transponder):
287                 index = self.getIndexForTransponder(transponder)
288                 if index not in self.indexlist:
289                         self.indexlist[index] = []
290                 self.indexlist[index].append(transponder)
291                 #print "self.indexlist:", self.indexlist
292         
293         # returns a string for the user representing a human readable output for index 
294         def getTextualIndexRepresentation(self, index):
295                 print "getTextualIndexRepresentation:", index
296                 text = ""
297                 
298                 text += nimmanager.getSatDescription(index[2]) + ", "
299                 
300                 if index[0] == 1:
301                         text += "Low Band, "
302                 else:
303                         text += "High Band, "
304                         
305                 if index[1] == 0:
306                         text += "H"
307                 else:
308                         text += "V"
309                 return text
310         
311         def fillTransponderList(self):
312                 self.clearTransponder()
313                 print "----------- fillTransponderList"
314                 print "index:", self.currentlyTestedIndex
315                 keys = self.indexlist.keys()
316                 if self.getContinueScanning():
317                         print "index:", self.getTextualIndexRepresentation(self.currentlyTestedIndex)
318                         for transponder in self.indexlist[self.currentlyTestedIndex]:
319                                 self.addTransponder(transponder)
320                         print "transponderList:", self.transponderlist
321                         return True
322                 else:
323                         return False
324                 
325         def progressCallback(self, progress):
326                 if progress[0] != self["sub_progress"].getRange():
327                         self["sub_progress"].setRange(progress[0])
328                 self["sub_progress"].setValue(progress[1])
329
330         # logic for scanning order of transponders
331         # on go getFirstIndex is called
332         def getFirstIndex(self):
333                 # TODO use other function to scan more randomly
334                 if self.test_type == self.TEST_TYPE_QUICK:
335                         self.myindex = 0
336                         keys = self.indexlist.keys()
337                         keys.sort(key = lambda a: a[2]) # sort by orbpos
338                         self["overall_progress"].setRange(len(keys))
339                         self["overall_progress"].setValue(self.myindex)
340                         return keys[0]
341                 elif self.test_type == self.TEST_TYPE_RANDOM:
342                         self.randomkeys = self.indexlist.keys()
343                         random.shuffle(self.randomkeys)
344                         self.myindex = 0
345                         self["overall_progress"].setRange(len(self.randomkeys))
346                         self["overall_progress"].setValue(self.myindex)
347                         return self.randomkeys[0]
348                 
349         # after each index is finished, getNextIndex is called to get the next index to scan 
350         def getNextIndex(self):
351                 # TODO use other function to scan more randomly
352                 if self.test_type == self.TEST_TYPE_QUICK:
353                         self.myindex += 1
354                         keys = self.indexlist.keys()
355                         keys.sort(key = lambda a: a[2]) # sort by orbpos
356                         
357                         self["overall_progress"].setValue(self.myindex)
358                         if self.myindex < len(keys):
359                                 return keys[self.myindex]
360                         else:
361                                 return None
362                 elif self.test_type == self.TEST_TYPE_RANDOM:
363                         self.myindex += 1
364                         keys = self.randomkeys
365                         
366                         self["overall_progress"].setValue(self.myindex)
367                         if self.myindex < len(keys):
368                                 return keys[self.myindex]
369                         else:
370                                 return None
371                                 
372         # after each index is finished and the next index is returned by getNextIndex
373         # the algorithm checks, if we should continue scanning
374         def getContinueScanning(self):
375                 if self.test_type == self.TEST_TYPE_QUICK or self.test_type == self.TEST_TYPE_RANDOM:
376                         return (self.myindex < len(self.indexlist.keys()))
377                 
378         def addResult(self, index, status, failedTune, successfullyTune):
379                 self.results[index] = self.results.get(index, {"failed": [], "successful": [], "status": None})
380                 self.resultsstatus[status] = self.resultsstatus.get(status, [])
381                 
382                 self.results[index]["status"] = status
383                 self.results[index]["failed"] = failedTune
384                 self.results[index]["successful"] = successfullyTune
385                 
386                 self.resultsstatus[status].append(index)
387         
388         def finishedChecking(self):
389                 print "finishedChecking"
390                 TuneTest.finishedChecking(self)
391
392                 if not self.results.has_key(self.currentlyTestedIndex):
393                         self.results[self.currentlyTestedIndex] = {"failed": [], "successful": [], "status": None}
394                 
395                 if len(self.failedTune) > 0 and len(self.successfullyTune) > 0:
396                         self.changeProgressListStatus(self.currentlyTestedIndex, "with errors")
397                         self["witherrors_counter"].setText(str(int(self["witherrors_counter"].getText()) + 1))
398                         self.addResult(self.currentlyTestedIndex, "with_errors", self.failedTune, self.successfullyTune)
399                 elif len(self.failedTune) == 0 and len(self.successfullyTune) == 0:
400                         self.changeProgressListStatus(self.currentlyTestedIndex, "not tested")
401                         self["untestable_counter"].setText(str(int(self["untestable_counter"].getText()) + 1))
402                         self.addResult(self.currentlyTestedIndex, "untestable", self.failedTune, self.successfullyTune)
403                 elif len(self.failedTune) > 0:
404                         self.changeProgressListStatus(self.currentlyTestedIndex, "failed")
405                         self["failed_counter"].setText(str(int(self["failed_counter"].getText()) + len(self.failedTune)))
406                         self.addResult(self.currentlyTestedIndex, "failed", self.failedTune, self.successfullyTune)
407                 else:
408                         self.changeProgressListStatus(self.currentlyTestedIndex, "successful")
409                         self["succeeded_counter"].setText(str(int(self["succeeded_counter"].getText()) + len(self.successfullyTune)))
410                         self.addResult(self.currentlyTestedIndex, "successful", self.failedTune, self.successfullyTune)
411                         
412                         
413                 #self["failed_counter"].setText(str(int(self["failed_counter"].getText()) + len(self.failedTune)))
414                 #self["succeeded_counter"].setText(str(int(self["succeeded_counter"].getText()) + len(self.successfullyTune)))
415                 #if len(self.failedTune) == 0 and len(self.successfullyTune) == 0:
416                         #self["untestable_counter"].setText(str(int(self["untestable_counter"].getText()) + 1))
417                         
418                 self.currentlyTestedIndex = self.getNextIndex()
419                 self.addProgressListItem(self.currentlyTestedIndex)
420                 
421                 if self.fillTransponderList():
422                         self.run(checkPIDs = True)
423                 else:
424                         self.running = False
425                         self["progress_list"].setIndex(0)
426                         print "results:", self.results
427                         print "resultsstatus:", self.resultsstatus
428                         if self.log:
429                                 file = open("/media/hdd/diseqctester.log", "w")
430                                 self.setResultType(ResultParser.TYPE_ALL)
431                                 file.write(self.getTextualResult())
432                                 file.close()
433                                 self.session.open(MessageBox, text=_("The results have been written to %s.") % "/media/hdd/diseqctester.log", type = MessageBox.TYPE_INFO)
434
435         def go(self):
436                 self.running = True
437                 self["failed_counter"].setText("0")
438                 self["succeeded_counter"].setText("0")
439                 self["untestable_counter"].setText("0")
440                 self.currentlyTestedIndex = self.getFirstIndex()
441                 
442                 self.clearProgressList()
443                 self.addProgressListItem(self.currentlyTestedIndex)
444                 
445                 if self.fillTransponderList():
446                         self.run(True)
447
448         def keyCancel(self):
449                 self.close()
450                 
451         def select(self):
452                 print "selectedIndex:", self["progress_list"].getCurrent()[0]
453                 if not self.running:
454                         index = self["progress_list"].getCurrent()[0]
455                         #self.setResultType(ResultParser.TYPE_BYORBPOS)
456                         #self.setResultParameter(index[2])
457                         self.setResultType(ResultParser.TYPE_BYINDEX)
458                         self.setResultParameter(index)
459                         #self.setResultType(ResultParser.TYPE_ALL)
460                         self.session.open(TextBox, self.getTextualResult())
461         
462         def selectionChanged(self):
463                 print "selection changed"
464                 if len(self.list) > 0 and not self.running:
465                         self["CmdText"].setText(_("Press OK to get further details for %s") % str(self["progress_list"].getCurrent()[1]))
466
467 class DiseqcTesterTestTypeSelection(Screen, ConfigListScreen):
468         skin = """<screen position="80,95" size="560,412" title="DiSEqC Tester Test Settings">
469                 <widget name="config" position="10,10" size="540,402" scrollbarMode="showOnDemand" />
470         </screen>
471         """
472         def __init__(self, session, feid):
473                 Screen.__init__(self, session)
474                 self.feid = feid
475                 
476                 self.list = []
477                 ConfigListScreen.__init__(self, self.list)
478                 
479                 self["actions"] = ActionMap(["SetupActions"],
480                 {
481                         "cancel": self.keyCancel
482                 }, -2)
483                 
484                 self.createSetup()
485                 
486         def createSetup(self):
487                 self.testtype = ConfigSelection(choices={"quick": _("Quick"), "random": _("Random")}, default = "quick")
488                 self.testtypeEntry = getConfigListEntry(_("Test Type"), self.testtype)
489                 self.list.append(self.testtypeEntry)
490                 
491                 self.loopsfailed = ConfigSelection(choices={"-1": "Every known", "1": "1", "2": "2", "3": "3", "4": "4", "5": "5", "6": "6", "7": "7", "8": "8"}, default = "3")
492                 self.loopsfailedEntry = getConfigListEntry(_("Stop testing plane after # failed transponders"), self.loopsfailed)
493                 self.list.append(self.loopsfailedEntry)
494                 
495                 self.loopssuccessful = ConfigSelection(choices={"-1": "Every known", "1": "1", "2": "2", "3": "3", "4": "4", "5": "5", "6": "6", "7": "7", "8": "8"}, default = "1")
496                 self.loopssuccessfulEntry = getConfigListEntry(_("Stop testing plane after # successful transponders"), self.loopssuccessful)
497                 self.list.append(self.loopssuccessfulEntry)
498                 
499                 self.log = ConfigYesNo(False)
500                 if harddiskmanager.HDDCount() > 0:
501                         self.logEntry = getConfigListEntry(_("Log results to harddisk"), self.log)
502                         self.list.append(self.logEntry)
503                                         
504                 self["config"].list = self.list
505                 self["config"].l.setList(self.list)
506                 
507         def keyOK(self):
508                 print self.testtype.getValue()
509                 testtype = DiseqcTester.TEST_TYPE_QUICK
510                 if self.testtype.getValue() == "quick":
511                         testtype = DiseqcTester.TEST_TYPE_QUICK
512                 elif self.testtype.getValue() == "random":
513                         testtype = DiseqcTester.TEST_TYPE_RANDOM
514                 elif self.testtype.getValue() == "complete":
515                         testtype = DiseqcTester.TEST_TYPE_COMPLETE
516                 self.session.open(DiseqcTester, feid = self.feid, test_type = testtype, loopsfailed = int(self.loopsfailed.value), loopssuccessful = int(self.loopssuccessful.value), log = self.log.value)
517         
518         def keyCancel(self):
519                 self.close()
520
521 class DiseqcTesterNimSelection(NimSelection):
522         skin = """
523                 <screen position="160,123" size="400,330" title="Choose Tuner">
524                 <widget source="nimlist" render="Listbox" position="0,0" size="380,300" scrollbarMode="showOnDemand">
525                         <convert type="TemplatedMultiContent">
526                                 {"template": [
527                                                 MultiContentEntryText(pos = (10, 5), size = (360, 30), flags = RT_HALIGN_LEFT, text = 1), # index 1 is the nim name,
528                                                 MultiContentEntryText(pos = (50, 30), size = (320, 30), font = 1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is a description of the nim settings,
529                                         ],
530                                  "fonts": [gFont("Regular", 20), gFont("Regular", 15)],
531                                  "itemHeight": 70
532                                 }
533                         </convert>
534                 </widget>
535         </screen>"""
536                 
537         def __init__(self, session, args = None):
538                 NimSelection.__init__(self, session)
539
540         def setResultClass(self):
541                 #self.resultclass = DiseqcTester
542                 self.resultclass = DiseqcTesterTestTypeSelection
543                 
544         def showNim(self, nim):
545                 nimConfig = nimmanager.getNimConfig(nim.slot)
546                 if nim.isCompatible("DVB-S"):
547                         if nimConfig.configMode.value in ["loopthrough", "equal", "satposdepends", "nothing"]:
548                                 return False
549                         if nimConfig.configMode.value == "simple":
550                                 if nimConfig.diseqcMode.value == "positioner":
551                                         return True
552                         return True
553                 return False
554
555 def DiseqcTesterMain(session, **kwargs):
556         session.open(DiseqcTesterNimSelection)
557         
558 def autostart(reason, **kwargs):
559         resourcemanager.addResource("DiseqcTester", DiseqcTesterMain)
560
561 def Plugins(**kwargs):
562         return [ PluginDescriptor(name="DiSEqC Tester", description=_("Test DiSEqC settings"), where = PluginDescriptor.WHERE_PLUGINMENU, fnc=DiseqcTesterMain),
563                         PluginDescriptor(where = PluginDescriptor.WHERE_AUTOSTART, fnc = autostart)]