dont start timers as recurring timers... this is better for blocking syscalls
[enigma2.git] / lib / python / Plugins / SystemPlugins / PositionerSetup / plugin.py
1 from enigma import eTimer, eDVBSatelliteEquipmentControl, eDVBResourceManager, \
2         eDVBDiseqcCommand, eDVBFrontendParametersSatellite, eDVBFrontendParameters,\
3         iDVBFrontend
4
5 from Screens.Screen import Screen
6 from Screens.ScanSetup import ScanSetup
7 from Screens.MessageBox import MessageBox
8 from Plugins.Plugin import PluginDescriptor
9
10 from Components.Label import Label
11 from Components.ConfigList import ConfigList
12 from Components.TunerInfo import TunerInfo
13 from Components.ActionMap import ActionMap
14 from Components.NimManager import nimmanager
15 from Components.MenuList import MenuList
16 from Components.config import ConfigSatlist, ConfigNothing, ConfigSelection, ConfigSubsection, KEY_LEFT, KEY_RIGHT, getConfigListEntry
17
18 from time import sleep
19
20 class PositionerSetup(Screen):
21         skin = """
22                 <screen position="100,100" size="560,400" title="Positioner setup..." >
23                         <widget name="list" position="100,0" size="350,155" />
24
25                         <widget name="red" position="0,155" size="140,80" backgroundColor="red" halign="center" valign="center" font="Regular;21" />
26                         <widget name="green" position="140,155" size="140,80" backgroundColor="green" halign="center" valign="center" font="Regular;21" />
27                         <widget name="yellow" position="280,155" size="140,80" backgroundColor="yellow" halign="center" valign="center" font="Regular;21" />
28                         <widget name="blue" position="420,155" size="140,80" backgroundColor="blue" halign="center" valign="center" font="Regular;21" />
29                         
30                         <widget name="snr" text="SNR:" position="0,245" size="60,22" font="Regular;21" />
31                         <widget name="agc" text="AGC:" position="0,270" size="60,22" font="Regular;21" />
32                         <widget name="ber" text="BER:" position="0,295" size="60,22" font="Regular;21" />
33                         <widget name="lock" text="Lock:" position="0,320" size="60,22" font="Regular;21" />
34                         <widget name="snr_percentage" position="220,245" size="60,22" font="Regular;21" />
35                         <widget name="agc_percentage" position="220,270" size="60,22" font="Regular;21" />
36                         <widget name="ber_value" position="220,295" size="60,22" font="Regular;21" />
37                         <widget name="lock_state" position="60,320" size="150,22" font="Regular;21" />
38                         <widget name="snr_bar" position="60,245" size="150,22" />
39                         <widget name="agc_bar" position="60,270" size="150,22" />
40                         <widget name="ber_bar" position="60,295" size="150,22" />
41
42                         <widget name="frequency" text="Frequency:" position="300,245" size="120,22" font="Regular;21" />
43                         <widget name="symbolrate" text="Symbolrate:" position="300,270" size="120,22" font="Regular;21" />
44                         <widget name="fec" text="FEC:" position="300,295" size="120,22" font="Regular;21" />
45                         <widget name="frequency_value" position="420,245" size="120,22" font="Regular;21" />
46                         <widget name="symbolrate_value" position="420,270" size="120,22" font="Regular;21" />
47                         <widget name="fec_value" position="420,295" size="120,22" font="Regular;21" />
48                 </screen>"""
49         def __init__(self, session, feid):
50                 self.skin = PositionerSetup.skin
51                 Screen.__init__(self, session)
52                 self.feid = feid
53                 self.oldref = None
54                 
55                 if not self.openFrontend():
56                         self.oldref = session.nav.getCurrentlyPlayingServiceReference()
57                         session.nav.stopService() # try to disable foreground service
58                         if not self.openFrontend():
59                                 if session.pipshown: # try to disable pip
60                                         session.pipshown = False
61                                         del session.pip
62                                         if not self.openFrontend():
63                                                 self.frontend = None # in normal case this should not happen
64
65                 self.frontendStatus = { }
66
67                 self.diseqc = Diseqc(self.frontend)
68                 self.tuner = Tuner(self.frontend)
69                 self.tuner.tune((0,0,0,0,0,0))
70                 
71                 self.createConfig()
72                 
73                 self.isMoving = False
74                 self.stopOnLock = False
75                 
76                 self.red = Label("")
77                 self["red"] = self.red
78                 self.green = Label("")
79                 self["green"] = self.green
80                 self.yellow = Label("")
81                 self["yellow"] = self.yellow
82                 self.blue = Label("")
83                 self["blue"] = self.blue
84                 
85                 self.list = []
86                 self["list"] = ConfigList(self.list)
87                 self.createSetup()
88                 
89                 self["snr"] = Label()
90                 self["agc"] = Label()
91                 self["ber"] = Label()
92                 self["lock"] = Label()
93                 self["snr_percentage"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, statusDict = self.frontendStatus)
94                 self["agc_percentage"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, statusDict = self.frontendStatus)
95                 self["ber_value"] = TunerInfo(TunerInfo.BER_VALUE, statusDict = self.frontendStatus)
96                 self["snr_bar"] = TunerInfo(TunerInfo.SNR_BAR, statusDict = self.frontendStatus)
97                 self["agc_bar"] = TunerInfo(TunerInfo.AGC_BAR, statusDict = self.frontendStatus)
98                 self["ber_bar"] = TunerInfo(TunerInfo.BER_BAR, statusDict = self.frontendStatus)
99                 self["lock_state"] = TunerInfo(TunerInfo.LOCK_STATE, statusDict = self.frontendStatus)
100
101                 self["frequency"] = Label()
102                 self["symbolrate"] = Label()
103                 self["fec"] = Label()
104
105                 self["frequency_value"] = Label("")
106                 self["symbolrate_value"] = Label("")
107                 self["fec_value"] = Label("")
108                 
109                 self["actions"] = ActionMap(["DirectionActions", "OkCancelActions", "ColorActions"],
110                 {
111                         "ok": self.go,
112                         "cancel": self.keyCancel,
113                         "up": self.up,
114                         "down": self.down,
115                         "left": self.left,
116                         "right": self.right,
117                         "red": self.redKey,
118                         "green": self.greenKey,
119                         "yellow": self.yellowKey,
120                         "blue": self.blueKey,
121                 }, -1)
122                 
123                 self.updateColors("tune")
124                 
125                 self.statusTimer = eTimer()
126                 self.statusTimer.callback.append(self.updateStatus)
127                 self.statusTimer.start(50, True)
128                 self.onClose.append(self.__onClose)
129
130         def __onClose(self):
131                 self.session.nav.playService(self.oldref)
132
133         def restartPrevService(self, yesno):
134                 if yesno:
135                         if self.frontend:
136                                 self.frontend = None
137                                 del self.raw_channel
138                 else:
139                         self.oldref=None
140                 self.close(None)        
141
142         def keyCancel(self):
143                 if self.oldref:
144                         self.session.openWithCallback(self.restartPrevService, MessageBox, _("Zap back to service before positioner setup?"), MessageBox.TYPE_YESNO)
145                 else:
146                         self.restartPrevService(False)
147
148         def openFrontend(self):
149                 res_mgr = eDVBResourceManager.getInstance()
150                 if res_mgr:
151                         self.raw_channel = res_mgr.allocateRawChannel(self.feid)
152                         if self.raw_channel:
153                                 self.frontend = self.raw_channel.getFrontend()
154                                 if self.frontend:
155                                         return True
156                                 else:
157                                         print "getFrontend failed"
158                         else:
159                                 print "getRawChannel failed"
160                 else:
161                         print "getResourceManager instance failed"
162                 return False
163
164         def createConfig(self):
165                 self.positioner_tune = ConfigNothing()
166                 self.positioner_move = ConfigNothing()
167                 self.positioner_finemove = ConfigNothing()
168                 self.positioner_limits = ConfigNothing()
169                 self.positioner_goto0 = ConfigNothing()
170                 storepos = []
171                 for x in range(1,255):
172                         storepos.append(str(x))
173                 self.positioner_storage = ConfigSelection(choices = storepos)
174
175         def createSetup(self):
176                 self.list.append((_("Tune"), self.positioner_tune, "tune"))
177                 self.list.append((_("Positioner movement"), self.positioner_move, "move"))
178                 self.list.append((_("Positioner fine movement"), self.positioner_finemove, "finemove"))
179                 self.list.append((_("Set limits"), self.positioner_limits, "limits"))
180                 self.list.append((_("Positioner storage"), self.positioner_storage, "storage"))
181                 self.list.append((_("Goto 0"), self.positioner_goto0, "goto0"))
182                 self["list"].l.setList(self.list)
183
184         def go(self):
185                 pass
186
187         def getCurrentConfigPath(self):
188                 return self["list"].getCurrent()[2]
189
190         def up(self):
191                 if not self.isMoving:
192                         self["list"].instance.moveSelection(self["list"].instance.moveUp)
193                         self.updateColors(self.getCurrentConfigPath())
194
195         def down(self):
196                 if not self.isMoving:
197                         self["list"].instance.moveSelection(self["list"].instance.moveDown)
198                         self.updateColors(self.getCurrentConfigPath())
199
200         def left(self):
201                 self["list"].handleKey(KEY_LEFT)
202
203         def right(self):
204                 self["list"].handleKey(KEY_RIGHT)
205
206         def updateColors(self, entry):
207                 if entry == "tune":
208                         self.red.setText(_("Tune"))
209                         self.green.setText("")
210                         self.yellow.setText("")
211                         self.blue.setText("")
212                 elif entry == "move":
213                         if self.isMoving:
214                                 self.red.setText(_("Stop"))
215                                 self.green.setText(_("Stop"))
216                                 self.yellow.setText(_("Stop"))
217                                 self.blue.setText(_("Stop"))
218                         else:
219                                 self.red.setText(_("Move west"))
220                                 self.green.setText(_("Search west"))
221                                 self.yellow.setText(_("Search east"))
222                                 self.blue.setText(_("Move east"))
223                 elif entry == "finemove":
224                         self.red.setText("")
225                         self.green.setText(_("Step west"))
226                         self.yellow.setText(_("Step east"))
227                         self.blue.setText("")
228                 elif entry == "limits":
229                         self.red.setText(_("Limits off"))
230                         self.green.setText(_("Limit west"))
231                         self.yellow.setText(_("Limit east"))
232                         self.blue.setText(_("Limits on"))
233                 elif entry == "storage":
234                         self.red.setText("")
235                         self.green.setText(_("Store position"))
236                         self.yellow.setText(_("Goto position"))
237                         self.blue.setText("")
238                 elif entry == "goto0":
239                         self.red.setText(_("Goto 0"))
240                         self.green.setText("")
241                         self.yellow.setText("")
242                         self.blue.setText("")
243                 else:
244                         self.red.setText("")
245                         self.green.setText("")
246                         self.yellow.setText("")
247                         self.blue.setText("")
248
249         def redKey(self):
250                 entry = self.getCurrentConfigPath()
251                 if entry == "move":
252                         if self.isMoving:
253                                 self.diseqccommand("stop")
254                                 self.isMoving = False
255                                 self.stopOnLock = False
256                         else:
257                                 self.diseqccommand("moveWest", 0)
258                                 self.isMoving = True
259                         self.updateColors("move")
260                 elif entry == "limits":
261                         self.diseqccommand("limitOff")
262                 elif entry == "tune":
263                         self.session.openWithCallback(self.tune, TunerScreen, self.feid)
264                 elif entry == "goto0":
265                         print "move to position 0"
266                         self.diseqccommand("moveTo", 0)
267
268         def greenKey(self):
269                 entry = self.getCurrentConfigPath()
270                 if entry == "move":
271                         if self.isMoving:
272                                 self.diseqccommand("stop")
273                                 self.isMoving = False
274                                 self.stopOnLock = False
275                         else:
276                                 self.isMoving = True
277                                 self.stopOnLock = True
278                                 self.diseqccommand("moveWest", 0)
279                         self.updateColors("move")
280                 elif entry == "finemove":
281                         print "stepping west"
282                         self.diseqccommand("moveWest", 0xFF) # one step
283                 elif entry == "storage":
284                         print "store at position", int(self.positioner_storage.value)
285                         self.diseqccommand("store", int(self.positioner_storage.value))
286                 elif entry == "limits":
287                         self.diseqccommand("limitWest")
288
289         def yellowKey(self):
290                 entry = self.getCurrentConfigPath()
291                 if entry == "move":
292                         if self.isMoving:
293                                 self.diseqccommand("stop")
294                                 self.isMoving = False
295                                 self.stopOnLock = False
296                         else:
297                                 self.isMoving = True
298                                 self.stopOnLock = True
299                                 self.diseqccommand("moveEast", 0)
300                         self.updateColors("move")
301                 elif entry == "finemove":
302                         print "stepping east"
303                         self.diseqccommand("moveEast", 0xFF) # one step
304                 elif entry == "storage":
305                         print "move to position", int(self.positioner_storage.value)
306                         self.diseqccommand("moveTo", int(self.positioner_storage.value))
307                 elif entry == "limits":
308                         self.diseqccommand("limitEast")
309
310         def blueKey(self):
311                 entry = self.getCurrentConfigPath()
312                 if entry == "move":
313                         if self.isMoving:
314                                 self.diseqccommand("stop")
315                                 self.isMoving = False
316                                 self.stopOnLock = False
317                         else:
318                                 self.diseqccommand("moveEast", 0)
319                                 self.isMoving = True
320                         self.updateColors("move")
321                         print "moving east"
322                 elif entry == "limits":
323                         self.diseqccommand("limitOn")
324
325         def diseqccommand(self, cmd, param = 0):
326                 self.diseqc.command(cmd, param)
327                 self.tuner.retune()
328
329         def updateStatus(self):
330                 if self.frontend:
331                         self.frontend.getFrontendStatus(self.frontendStatus)
332                 self["snr_percentage"].update()
333                 self["agc_percentage"].update()
334                 self["ber_value"].update()
335                 self["snr_bar"].update()
336                 self["agc_bar"].update()
337                 self["ber_bar"].update()
338                 self["lock_state"].update()
339                 transponderdata = self.tuner.getTransponderData()
340                 self["frequency_value"].setText(str(transponderdata.get("frequency")))
341                 self["symbolrate_value"].setText(str(transponderdata.get("symbol_rate")))
342                 self["fec_value"].setText(str(transponderdata.get("fec_inner")))
343                 if self.frontendStatus.get("tuner_locked", 0) == 1 and self.isMoving and self.stopOnLock:
344                         self.diseqccommand("stop")
345                         self.isMoving = False
346                         self.stopOnLock = False
347                         self.updateColors(self.getCurrentConfigPath())
348                 self.statusTimer.start(50, True)
349
350         def tune(self, transponder):
351                 if transponder is not None:
352                         self.tuner.tune(transponder)
353
354 class Diseqc:
355         def __init__(self, frontend):
356                 self.frontend = frontend
357
358         def command(self, what, param = 0):
359                 if self.frontend:
360                         cmd = eDVBDiseqcCommand()
361                         if what == "moveWest":
362                                 string = 'e03169' + ("%02x" % param)
363                         elif what == "moveEast":
364                                 string = 'e03168' + ("%02x" % param)
365                         elif what == "moveTo":
366                                 string = 'e0316b' + ("%02x" % param)
367                         elif what == "store":
368                                 string = 'e0316a' + ("%02x" % param)
369                         elif what == "limitOn":
370                                 string = 'e0316a00'
371                         elif what == "limitOff":
372                                 string = 'e03163'
373                         elif what == "limitEast":
374                                 string = 'e03166'
375                         elif what == "limitWest":
376                                 string = 'e03167'
377                         else:
378                                 string = 'e03160' #positioner stop
379                         
380                         print "diseqc command:",
381                         print string
382                         cmd.setCommandString(string)
383                         self.frontend.setTone(iDVBFrontend.toneOff)
384                         sleep(0.015) # wait 15msec after disable tone
385                         self.frontend.sendDiseqc(cmd)
386                         if string == 'e03160': #positioner stop
387                                 sleep(0.05)
388                                 self.frontend.sendDiseqc(cmd) # send 2nd time
389
390 class Tuner:
391         def __init__(self, frontend):
392                 self.frontend = frontend
393
394         def tune(self, transponder):
395                 print "tuning to transponder with data", transponder
396                 parm = eDVBFrontendParametersSatellite()
397                 parm.frequency = transponder[0] * 1000
398                 parm.symbol_rate = transponder[1] * 1000
399                 parm.polarisation = transponder[2]
400                 parm.fec = transponder[3]
401                 parm.inversion = transponder[4]
402                 parm.orbital_position = transponder[5]
403                 parm.system = 0  # FIXMEE !! HARDCODED DVB-S (add support for DVB-S2)
404                 parm.modulation = 1 # FIXMEE !! HARDCODED QPSK
405                 feparm = eDVBFrontendParameters()
406                 feparm.setDVBS(parm, True)
407                 self.lastparm = feparm
408                 if self.frontend:
409                         self.frontend.tune(feparm)
410
411         def retune(self):
412                 if self.frontend:
413                         self.frontend.tune(self.lastparm)
414
415         def getTransponderData(self):
416                 ret = { }
417                 if self.frontend:
418                         self.frontend.getTransponderData(ret, True)
419                 return ret
420
421 tuning = None
422
423 class TunerScreen(ScanSetup):
424         skin = """
425                 <screen position="90,100" size="520,400" title="Tune">
426                         <widget name="config" position="20,10" size="460,350" scrollbarMode="showOnDemand" />
427                         <widget name="introduction" position="20,360" size="350,30" font="Regular;23" />
428                 </screen>"""
429
430         def __init__(self, session, feid):
431                 self.feid = feid
432                 ScanSetup.__init__(self, session)
433                 self["introduction"].setText("")
434
435         def createSetup(self):
436                 self.typeOfTuningEntry = None
437                 self.satEntry = None
438                 self.list = []
439                 self.typeOfTuningEntry = getConfigListEntry(_('Tune'), tuning.type)
440                 self.list.append(self.typeOfTuningEntry)
441                 self.satEntry = getConfigListEntry(_('Satellite'), tuning.sat)
442                 self.list.append(self.satEntry)
443                 if tuning.type.value == "manual_transponder":
444                         self.list.append(getConfigListEntry(_('Frequency'), self.scan_sat.frequency))
445                         self.list.append(getConfigListEntry(_('Inversion'), self.scan_sat.inversion))
446                         self.list.append(getConfigListEntry(_('Symbol Rate'), self.scan_sat.symbolrate))
447                         self.list.append(getConfigListEntry(_("Polarity"), self.scan_sat.polarization))
448                         self.list.append(getConfigListEntry(_("FEC"), self.scan_sat.fec))
449                 elif tuning.type.value == "predefined_transponder":
450                         self.list.append(getConfigListEntry(_("Transponder"), tuning.transponder))
451                 self["config"].list = self.list
452                 self["config"].l.setList(self.list)
453
454         def newConfig(self):
455                 if self["config"].getCurrent() == self.typeOfTuningEntry:
456                         self.createSetup()
457                 elif self["config"].getCurrent() == self.satEntry:
458                         self.createSetup()
459
460         def createConfig(self, foo):
461                 global tuning
462                 if not tuning:
463                         tuning = ConfigSubsection()
464                         tuning.type = ConfigSelection(
465                                 default = "manual_transponder",
466                                 choices = { "manual_transponder" : _("Manual transponder"),
467                                                         "predefined_transponder" : _("Predefined transponder") } )
468                         tuning.sat = ConfigSatlist(list=nimmanager.getRotorSatListForNim(self.feid))
469                         tuning.sat.addNotifier(self.tuningSatChanged)
470                         self.updateTransponders()
471                         TunerScreenConfigCreated = True
472                 ScanSetup.createConfig(self, None)
473
474         def tuningSatChanged(self, *parm):
475                 self.updateTransponders()
476
477         def updateTransponders(self):
478                 if len(tuning.sat.choices):
479                         transponderlist = nimmanager.getTransponders(int(tuning.sat.value))
480                         tps = []
481                         cnt=0
482                         for x in transponderlist:
483                                 if x[3] == 0:
484                                         pol = "H"
485                                 elif x[3] == 1:
486                                         pol = "V"
487                                 elif x[3] == 2:
488                                         pol = "CL"
489                                 elif x[3] == 3:
490                                         pol = "CR"
491                                 else:
492                                         pol = "??"
493                                 if x[4] == 0:
494                                         fec = "FEC_AUTO"
495                                 elif x[4] == 1:
496                                         fec = "FEC_1_2"
497                                 elif x[4] == 2:
498                                         fec = "FEC_2_3"
499                                 elif x[4] == 3:
500                                         fec = "FEC_3_4"
501                                 elif x[4] == 4:
502                                         fec = "FEC_5_6"
503                                 elif x[4] == 5:
504                                         fec = "FEC_7_8"
505                                 elif x[4] == 6:
506                                         fec = "FEC_8_9"
507                                 elif x[4] == 7:
508                                         fec = "FEC_3_5"
509                                 elif x[4] == 8:
510                                         fec = "FEC_4_5"
511                                 elif x[4] == 9:
512                                         fec = "FEC_9_10"
513                                 elif x[4] == 15:
514                                         fec = "FEC_None"
515                                 else:
516                                         fec = "FEC_Unknown"
517                                 tps.append(str(x[1]) + "," + str(x[2]) + "," + pol + "," + fec)
518                         tuning.transponder = ConfigSelection(choices=tps)
519
520         def keyGo(self):
521                 returnvalue = (0, 0, 0, 0, 0, 0)
522                 satpos = int(tuning.sat.value)
523                 if tuning.type.value == "manual_transponder":
524                         returnvalue = (
525                                 self.scan_sat.frequency.value,
526                                 self.scan_sat.symbolrate.value,
527                                 self.scan_sat.polarization.index,
528                                 self.scan_sat.fec.index,
529                                 self.scan_sat.inversion.index,
530                                 satpos)
531                 elif tuning.type.value == "predefined_transponder":
532                         transponder = nimmanager.getTransponders(satpos)[tuning.transponder.index]
533                         returnvalue = (int(transponder[1] / 1000), int(transponder[2] / 1000), transponder[3], transponder[4], 2, satpos)
534                 self.close(returnvalue)
535
536         def keyCancel(self):
537                 self.close(None)
538
539 class RotorNimSelection(Screen):
540         skin = """
541                 <screen position="140,165" size="400,100" title="select Slot">
542                         <widget name="nimlist" position="20,10" size="360,75" />
543                 </screen>"""
544
545         def __init__(self, session):
546                 Screen.__init__(self, session)
547
548                 nimlist = nimmanager.getNimListOfType("DVB-S")
549                 nimMenuList = []
550                 for x in nimlist:
551                         nimMenuList.append((nimmanager.nim_slots[x].friendly_full_description, x))
552                 
553                 self["nimlist"] = MenuList(nimMenuList)
554
555                 self["actions"] = ActionMap(["OkCancelActions"],
556                 {
557                         "ok": self.okbuttonClick ,
558                         "cancel": self.close
559                 }, -1)
560
561         def okbuttonClick(self):
562                 selection = self["nimlist"].getCurrent()
563                 self.session.open(PositionerSetup, selection[1])
564
565 def PositionerMain(session, **kwargs):
566         nimList = nimmanager.getNimListOfType("DVB-S")
567         if len(nimList) == 0:
568                 session.open(MessageBox, _("No positioner capable frontend found."), MessageBox.TYPE_ERROR)
569         else:
570                 if session.nav.RecordTimer.isRecording():
571                         session.open(MessageBox, _("A recording is currently running. Please stop the recording before trying to configure the positioner."), MessageBox.TYPE_ERROR)
572                 else:
573                         usableNims = []
574                         for x in nimList:
575                                 configured_rotor_sats = nimmanager.getRotorSatListForNim(x)
576                                 if len(configured_rotor_sats) != 0:
577                                         usableNims.append(x)
578                         if len(usableNims) == 1:
579                                 session.open(PositionerSetup, usableNims[0])
580                         elif len(usableNims) > 1:
581                                 session.open(RotorNimSelection)
582                         else:
583                                 session.open(MessageBox, _("No tuner is configured for use with a diseqc positioner!"), MessageBox.TYPE_ERROR)
584
585 def PositionerSetupStart(menuid, **kwargs):
586         if menuid == "scan":
587                 return [(_("Positioner setup"), PositionerMain, "positioner_setup", None)]
588         else:
589                 return []
590
591 def Plugins(**kwargs):
592         if (nimmanager.hasNimType("DVB-S")):
593                 return PluginDescriptor(name=_("Positioner setup"), description="Setup your positioner", where = PluginDescriptor.WHERE_MENU, fnc=PositionerSetupStart)
594         else:
595                 return []