4ade7fe0a6e1828afa7218e7d150cf543098df05
[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, False)
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
349         def tune(self, transponder):
350                 if transponder is not None:
351                         self.tuner.tune(transponder)
352
353 class Diseqc:
354         def __init__(self, frontend):
355                 self.frontend = frontend
356
357         def command(self, what, param = 0):
358                 if self.frontend:
359                         cmd = eDVBDiseqcCommand()
360                         if what == "moveWest":
361                                 string = 'e03169' + ("%02x" % param)
362                         elif what == "moveEast":
363                                 string = 'e03168' + ("%02x" % param)
364                         elif what == "moveTo":
365                                 string = 'e0316b' + ("%02x" % param)
366                         elif what == "store":
367                                 string = 'e0316a' + ("%02x" % param)
368                         elif what == "limitOn":
369                                 string = 'e0316a00'
370                         elif what == "limitOff":
371                                 string = 'e03163'
372                         elif what == "limitEast":
373                                 string = 'e03166'
374                         elif what == "limitWest":
375                                 string = 'e03167'
376                         else:
377                                 string = 'e03160' #positioner stop
378                         
379                         print "diseqc command:",
380                         print string
381                         cmd.setCommandString(string)
382                         self.frontend.setTone(iDVBFrontend.toneOff)
383                         sleep(0.015) # wait 15msec after disable tone
384                         self.frontend.sendDiseqc(cmd)
385                         if string == 'e03160': #positioner stop
386                                 sleep(0.05)
387                                 self.frontend.sendDiseqc(cmd) # send 2nd time
388
389 class Tuner:
390         def __init__(self, frontend):
391                 self.frontend = frontend
392
393         def tune(self, transponder):
394                 print "tuning to transponder with data", transponder
395                 parm = eDVBFrontendParametersSatellite()
396                 parm.frequency = transponder[0] * 1000
397                 parm.symbol_rate = transponder[1] * 1000
398                 parm.polarisation = transponder[2]
399                 parm.fec = transponder[3]
400                 parm.inversion = transponder[4]
401                 parm.orbital_position = transponder[5]
402                 parm.system = 0  # FIXMEE !! HARDCODED DVB-S (add support for DVB-S2)
403                 parm.modulation = 1 # FIXMEE !! HARDCODED QPSK
404                 feparm = eDVBFrontendParameters()
405                 feparm.setDVBS(parm, True)
406                 self.lastparm = feparm
407                 if self.frontend:
408                         self.frontend.tune(feparm)
409
410         def retune(self):
411                 if self.frontend:
412                         self.frontend.tune(self.lastparm)
413
414         def getTransponderData(self):
415                 ret = { }
416                 if self.frontend:
417                         self.frontend.getTransponderData(ret, True)
418                 return ret
419
420 tuning = None
421
422 class TunerScreen(ScanSetup):
423         skin = """
424                 <screen position="90,100" size="520,400" title="Tune">
425                         <widget name="config" position="20,10" size="460,350" scrollbarMode="showOnDemand" />
426                         <widget name="introduction" position="20,360" size="350,30" font="Regular;23" />
427                 </screen>"""
428
429         def __init__(self, session, feid):
430                 self.feid = feid
431                 ScanSetup.__init__(self, session)
432                 self["introduction"].setText("")
433
434         def createSetup(self):
435                 self.typeOfTuningEntry = None
436                 self.satEntry = None
437                 self.list = []
438                 self.typeOfTuningEntry = getConfigListEntry(_('Tune'), tuning.type)
439                 self.list.append(self.typeOfTuningEntry)
440                 self.satEntry = getConfigListEntry(_('Satellite'), tuning.sat)
441                 self.list.append(self.satEntry)
442                 if tuning.type.value == "manual_transponder":
443                         self.list.append(getConfigListEntry(_('Frequency'), self.scan_sat.frequency))
444                         self.list.append(getConfigListEntry(_('Inversion'), self.scan_sat.inversion))
445                         self.list.append(getConfigListEntry(_('Symbol Rate'), self.scan_sat.symbolrate))
446                         self.list.append(getConfigListEntry(_("Polarity"), self.scan_sat.polarization))
447                         self.list.append(getConfigListEntry(_("FEC"), self.scan_sat.fec))
448                 elif tuning.type.value == "predefined_transponder":
449                         self.list.append(getConfigListEntry(_("Transponder"), tuning.transponder))
450                 self["config"].list = self.list
451                 self["config"].l.setList(self.list)
452
453         def newConfig(self):
454                 if self["config"].getCurrent() == self.typeOfTuningEntry:
455                         self.createSetup()
456                 elif self["config"].getCurrent() == self.satEntry:
457                         self.createSetup()
458
459         def createConfig(self, foo):
460                 global tuning
461                 if not tuning:
462                         tuning = ConfigSubsection()
463                         tuning.type = ConfigSelection(
464                                 default = "manual_transponder",
465                                 choices = { "manual_transponder" : _("Manual transponder"),
466                                                         "predefined_transponder" : _("Predefined transponder") } )
467                         tuning.sat = ConfigSatlist(list=nimmanager.getRotorSatListForNim(self.feid))
468                         tuning.sat.addNotifier(self.tuningSatChanged)
469                         self.updateTransponders()
470                         TunerScreenConfigCreated = True
471                 ScanSetup.createConfig(self, None)
472
473         def tuningSatChanged(self, *parm):
474                 self.updateTransponders()
475
476         def updateTransponders(self):
477                 if len(tuning.sat.choices):
478                         transponderlist = nimmanager.getTransponders(int(tuning.sat.value))
479                         tps = []
480                         cnt=0
481                         for x in transponderlist:
482                                 if x[3] == 0:
483                                         pol = "H"
484                                 elif x[3] == 1:
485                                         pol = "V"
486                                 elif x[3] == 2:
487                                         pol = "CL"
488                                 elif x[3] == 3:
489                                         pol = "CR"
490                                 else:
491                                         pol = "??"
492                                 if x[4] == 0:
493                                         fec = "FEC_AUTO"
494                                 elif x[4] == 1:
495                                         fec = "FEC_1_2"
496                                 elif x[4] == 2:
497                                         fec = "FEC_2_3"
498                                 elif x[4] == 3:
499                                         fec = "FEC_3_4"
500                                 elif x[4] == 4:
501                                         fec = "FEC_5_6"
502                                 elif x[4] == 5:
503                                         fec = "FEC_7_8"
504                                 elif x[4] == 6:
505                                         fec = "FEC_8_9"
506                                 elif x[4] == 7:
507                                         fec = "FEC_3_5"
508                                 elif x[4] == 8:
509                                         fec = "FEC_4_5"
510                                 elif x[4] == 9:
511                                         fec = "FEC_9_10"
512                                 elif x[4] == 15:
513                                         fec = "FEC_None"
514                                 else:
515                                         fec = "FEC_Unknown"
516                                 tps.append(str(x[1]) + "," + str(x[2]) + "," + pol + "," + fec)
517                         tuning.transponder = ConfigSelection(choices=tps)
518
519         def keyGo(self):
520                 returnvalue = (0, 0, 0, 0, 0, 0)
521                 satpos = int(tuning.sat.value)
522                 if tuning.type.value == "manual_transponder":
523                         returnvalue = (
524                                 self.scan_sat.frequency.value,
525                                 self.scan_sat.symbolrate.value,
526                                 self.scan_sat.polarization.index,
527                                 self.scan_sat.fec.index,
528                                 self.scan_sat.inversion.index,
529                                 satpos)
530                 elif tuning.type.value == "predefined_transponder":
531                         transponder = nimmanager.getTransponders(satpos)[tuning.transponder.index]
532                         returnvalue = (int(transponder[1] / 1000), int(transponder[2] / 1000), transponder[3], transponder[4], 2, satpos)
533                 self.close(returnvalue)
534
535         def keyCancel(self):
536                 self.close(None)
537
538 class NimSelection(Screen):
539         skin = """
540                 <screen position="140,165" size="400,100" title="select Slot">
541                         <widget name="nimlist" position="20,10" size="360,75" />
542                 </screen>"""
543
544         def __init__(self, session):
545                 Screen.__init__(self, session)
546
547                 nimlist = nimmanager.getNimListOfType("DVB-S")
548                 nimMenuList = []
549                 for x in nimlist:
550                         nimMenuList.append((nimmanager.nim_slots[x].friendly_full_description, x))
551                 
552                 self["nimlist"] = MenuList(nimMenuList)
553
554                 self["actions"] = ActionMap(["OkCancelActions"],
555                 {
556                         "ok": self.okbuttonClick ,
557                         "cancel": self.close
558                 }, -1)
559
560         def okbuttonClick(self):
561                 selection = self["nimlist"].getCurrent()
562                 self.session.open(PositionerSetup, selection[1])
563
564 def PositionerMain(session, **kwargs):
565         nimList = nimmanager.getNimListOfType("DVB-S")
566         if len(nimList) == 0:
567                 session.open(MessageBox, _("No positioner capable frontend found."), MessageBox.TYPE_ERROR)
568         else:
569                 if session.nav.RecordTimer.isRecording():
570                         session.open(MessageBox, _("A recording is currently running. Please stop the recording before trying to configure the positioner."), MessageBox.TYPE_ERROR)
571                 else:
572                         usableNims = []
573                         for x in nimList:
574                                 configured_rotor_sats = nimmanager.getRotorSatListForNim(x)
575                                 if len(configured_rotor_sats) != 0:
576                                         usableNims.append(x)
577                         if len(usableNims) == 1:
578                                 session.open(PositionerSetup, usableNims[0])
579                         elif len(usableNims) > 1:
580                                 session.open(NimSelection)
581                         else:
582                                 session.open(MessageBox, _("No tuner is configured for use with a diseqc positioner!"), MessageBox.TYPE_ERROR)
583
584 def PositionerSetupStart(menuid, **kwargs):
585         if menuid == "scan":
586                 return [(_("Positioner setup"), PositionerMain, "positioner_setup", None)]
587         else:
588                 return []
589
590 def Plugins(**kwargs):
591         if (nimmanager.hasNimType("DVB-S")):
592                 return PluginDescriptor(name=_("Positioner setup"), description="Setup your positioner", where = PluginDescriptor.WHERE_MENU, fnc=PositionerSetupStart)
593         else:
594                 return []