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