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