fix rotor position in infobar for motorized tuner. thx Dimitrij
[openblackhole/openblackhole-enigma2.git] / lib / python / Screens / Dish.py
1 # -*- coding: utf-8 -*-
2 from Screen import Screen
3 from Components.Pixmap import Pixmap
4 from Components.config import config, ConfigInteger
5 from Components.Sources.Boolean import Boolean
6 from Components.Label import Label
7 from Components.ProgressBar import ProgressBar
8 from Components.ServiceEventTracker import ServiceEventTracker
9 from enigma import eDVBSatelliteEquipmentControl, eTimer, iPlayableService
10 from Components.NimManager import nimmanager
11 from Components.Sources.FrontendStatus import FrontendStatus
12 from enigma import eServiceCenter, iServiceInformation
13 from ServiceReference import ServiceReference
14
15 INVALID_POSITION = 9999
16 config.misc.lastrotorposition = ConfigInteger(INVALID_POSITION)
17
18 class Dish(Screen):
19         STATE_HIDDEN = 0
20         STATE_SHOWN  = 1
21         skin = """
22                 <screen name="Dish" flags="wfNoBorder" position="86,100" size="130,220" title="Dish" zPosition="1" backgroundColor="#11396D" >
23                         <widget name="Dishpixmap" position="0,0"  size="130,160" zPosition="-1" pixmap="skin_default/icons/dish.png" transparent="1" alphatest="on" />
24                         <widget name="turnTime"   position="5,0"   size="120,20" zPosition="1" font="Regular;20" halign="right" shadowColor="black" shadowOffset="-2,-2" transparent="1" />
25                         <widget name="From"       position="5,162" size="50,17" zPosition="1" font="Regular;17" halign="left"  shadowColor="black" shadowOffset="-2,-1" transparent="1"  />
26                         <widget name="posFrom"    position="57,160" size="70,20" zPosition="1" font="Regular;20" halign="left"  shadowColor="black" shadowOffset="-2,-2" transparent="1" />
27                         <widget name="Goto"       position="5,182"  size="50,17" zPosition="1" font="Regular;17" halign="left"  shadowColor="black" shadowOffset="-2,-1" transparent="1" />
28                         <widget name="posGoto"    position="57,180" size="70,20" zPosition="1" font="Regular;20" halign="left"  shadowColor="black" shadowOffset="-2,-2" transparent="1" />
29                         <widget name="tunerName"  position="5,144"  size="90,16" zPosition="2" font="Regular;14" halign="left"  shadowColor="black" shadowOffset="-2,-1" transparent="1" />
30                         <widget name="turnSpeed"  position="75,95" size="50,16" zPosition="2" font="Regular;14" halign="right" shadowColor="black" shadowOffset="-2,-1" transparent="1" />
31                         <widget source="session.FrontendStatus" render="Progress" position="5,205" size="120,10" pixmap="skin_default/bar_snr.png" zPosition="2" borderWidth="2" borderColor="#cccccc">
32                                 <convert type="FrontendInfo">SNR</convert>
33                         </widget>
34                 </screen>"""
35
36         def __init__(self, session):
37                 self.skin = Dish.skin
38                 Screen.__init__(self, session)
39
40                 self["Dishpixmap"] = Pixmap()
41                 self["turnTime"] = Label("")
42                 self["posFrom"] = Label("")
43                 self["posGoto"] = Label("")
44                 self["From"] = Label(_("From :"))
45                 self["Goto"] = Label(_("Goto :"))
46                 self["tunerName"] = Label("")
47                 self["turnSpeed"] = Label("")
48
49                 self.updateRotorSatList()
50                 self.rotorTimer = eTimer()
51                 self.rotorTimer.callback.append(self.updateRotorMovingState)
52                 self.turnTimer = eTimer()
53                 self.turnTimer.callback.append(self.turnTimerLoop)
54                 self.timeoutTimer = eTimer()
55                 self.timeoutTimer.callback.append(self.testIsTuned)
56
57                 config.usage.showdish.addNotifier(self.configChanged)
58                 self.configChanged(config.usage.showdish)
59
60                 self.rotor_pos = self.cur_orbpos = config.misc.lastrotorposition.value
61                 config.misc.lastrotorposition.addNotifier(self.rotorPositionChanged)
62                 self.turn_time = self.total_time = self.pmt_timeout = self.close_timeout = None
63                 self.cur_polar = 0
64                 self.__state = self.STATE_HIDDEN
65
66                 self.onShow.append(self.__onShow)
67                 self.onHide.append(self.__onHide)
68
69                 self.__event_tracker = ServiceEventTracker(screen=self,
70                         eventmap= {
71                                 iPlayableService.evStart: self.__serviceStarted,
72                                 iPlayableService.evTunedIn: self.__serviceTunedIn,
73                         })
74
75         def updateRotorSatList(self):
76                 self.available_sat = []
77                 for x in nimmanager.nim_slots:
78                         for sat in nimmanager.getRotorSatListForNim(x.slot):
79                                 if sat[0] not in self.available_sat:
80                                         self.available_sat.append(sat[0])
81
82         def updateRotorMovingState(self):
83                 moving = eDVBSatelliteEquipmentControl.getInstance().isRotorMoving()
84                 if moving:
85                         if self.cur_orbpos != INVALID_POSITION and self.cur_orbpos != config.misc.lastrotorposition.value:
86                                 config.misc.lastrotorposition.value = self.cur_orbpos
87                                 config.misc.lastrotorposition.save()
88                         if self.__state == self.STATE_HIDDEN:
89                                 self.show()
90
91         def turnTimerLoop(self):
92                 if self.total_time:
93                         self.turn_time -= 1
94                         self["turnTime"].setText(self.FormatTurnTime(self.turn_time))
95                         self.close_timeout -=1
96                         if self.close_timeout < 0:
97                                 print "[Dish] timeout!"
98                                 self.__toHide()
99
100         def __onShow(self):
101                 self.__state = self.STATE_SHOWN
102
103                 prev_rotor_pos = self.rotor_pos
104                 self.rotor_pos = self.cur_orbpos
105                 self.total_time = self.getTurnTime(prev_rotor_pos, self.rotor_pos, self.cur_polar)
106                 self.turn_time = self.total_time
107                 self.close_timeout = round(self.total_time * 1.25) # aded 25%
108
109                 self["posFrom"].setText(self.OrbToStr(prev_rotor_pos))
110                 self["posGoto"].setText(self.OrbToStr(self.rotor_pos))
111                 self["tunerName"].setText(self.getTunerName())
112                 if self.total_time == 0:
113                         self["turnTime"].setText("")
114                         self["turnSpeed"].setText("")
115                 else:
116                         self["turnTime"].setText(self.FormatTurnTime(self.turn_time))
117                         self["turnSpeed"].setText(str(self.getTurningSpeed(self.cur_polar)) + chr(176) + _("/s"))
118
119                 self.turnTimer.start(1000, False)
120
121         def __onHide(self):
122                 self.__state = self.STATE_HIDDEN
123                 self.turnTimer.stop()
124                 self.updateRotorSatList()
125
126         def __serviceStarted(self):
127                 if self.__state == self.STATE_SHOWN:
128                         self.hide()
129                 if not self.showdish:
130                         return
131
132                 service = self.session.nav.getCurrentService()
133                 info = service and service.info()
134                 data = info and info.getInfoObject(iServiceInformation.sTransponderData)
135                 if not data or data == -1:
136                         return
137
138                 tuner_type = data.get("tuner_type")
139                 if tuner_type and "DVB-S" in tuner_type:
140                         cur_orbpos = data.get("orbital_position", INVALID_POSITION)
141                         if cur_orbpos in self.available_sat:
142                                 self.cur_orbpos = cur_orbpos
143                                 self.cur_polar  = data.get("polarization", 0)
144                                 self.rotorTimer.start(500, False)
145
146         def __toHide(self):
147                 self.rotorTimer.stop()
148                 self.timeoutTimer.stop()
149                 if self.__state == self.STATE_SHOWN:
150                         self.hide()
151
152         def __serviceTunedIn(self):
153                 self.pmt_timeout = self.close_timeout
154                 self.timeoutTimer.start(500, False)
155
156         def testIsTuned(self):
157                 if self.pmt_timeout >= 0:
158                         service = self.session.nav.getCurrentService()
159                         info = service and service.info()
160                         pmt = info and info.getInfo(iServiceInformation.sPMTPID)
161                         if pmt >= 0:
162                                 print "[Dish] tuned, closing..."
163                                 self.__toHide()
164                         else:
165                                 self.pmt_timeout -= 0.5
166                 else:
167                         self.__toHide()
168                         print "[Dish] tuning failed"
169
170         def dishState(self):
171                 return self.__state
172
173         def configChanged(self, configElement):
174                 self.showdish = configElement.value
175
176         def rotorPositionChanged(self, configElement=None):
177                 if self.cur_orbpos != config.misc.lastrotorposition.value != INVALID_POSITION:
178                         self.rotor_pos = self.cur_orbpos = config.misc.lastrotorposition.value
179
180         def getTurnTime(self, start, end, pol=0):
181                 mrt = abs(start - end) if start and end else 0
182                 if mrt > 0:
183                         if (mrt > 1800):
184                                 mrt = 3600 - mrt
185                         if (mrt % 10):
186                                 mrt += 10
187                         mrt = round((mrt * 1000 / self.getTurningSpeed(pol) ) / 10000) + 3
188                 return mrt
189
190         def getTurningSpeed(self, pol=0):
191                 tuner = self.getCurrentTuner()
192                 if tuner is not None:
193                         nimConfig = nimmanager.getNimConfig(tuner)
194                         if nimConfig.configMode.value == "simple":
195                                 if "positioner" in nimConfig.diseqcMode.value:
196                                         nim = config.Nims[tuner]
197                                         if pol in (1, 3): # vertical
198                                                 return nim.turningspeedV.float
199                                         return nim.turningspeedH.float
200                         elif nimConfig.configMode.value == "advanced":
201                                 if self.cur_orbpos != INVALID_POSITION:
202                                         satlist = nimConfig.advanced.sat.keys()
203                                         if self.cur_orbpos in satlist:
204                                                 currSat = nimConfig.advanced.sat[self.cur_orbpos]
205                                                 lnbnum = int(currSat.lnb.value)
206                                                 currLnb = lnbnum and nimConfig.advanced.lnb[lnbnum]
207                                                 diseqcmode = currLnb and currLnb.diseqcMode.value or ""
208                                                 if diseqcmode == "1_2":
209                                                         if pol in (1, 3): # vertical
210                                                                 return currLnb.turningspeedV.float
211                                                         return currLnb.turningspeedH.float
212                 if pol in (1, 3):
213                         return 1.0
214                 return 1.5
215
216         def getCurrentTuner(self):
217                 service = self.session.nav.getCurrentService()
218                 feinfo = service and service.frontendInfo()
219                 tuner = feinfo and feinfo.getFrontendData()
220                 if tuner is not None:
221                         return tuner.get("tuner_number")
222                 return None
223
224         def getTunerName(self):
225                 nr = self.getCurrentTuner()
226                 if nr is not None:
227                         nims = nimmanager.nimList()
228                         if nr < 4:
229                                 return "".join(nims[nr].split(':')[:1])
230                         return " ".join((_("Tuner"),str(nr)))
231                 return ""
232
233         def OrbToStr(self, orbpos):
234                 if orbpos == INVALID_POSITION:
235                         return "N/A"
236                 if orbpos > 1800:
237                         orbpos = 3600 - orbpos
238                         return "%d.%d°W" % (orbpos/10, orbpos%10)
239                 return "%d.%d°E" % (orbpos/10, orbpos%10)
240
241         def FormatTurnTime(self, time):
242                 t = abs(time)
243                 return "%s%02d:%02d" % (time < 0 and "- " or "", t/60%60, t%60)
244
245 class Dishpip(Dish, Screen):
246         STATE_HIDDEN = 0
247         STATE_SHOWN  = 1
248         skin = """
249                 <screen name="Dishpip" flags="wfNoBorder" position="86,100" size="130,220" title="DishPiP" zPosition="1" backgroundColor="#11396D" >
250                         <widget source="Dishpixmap" render="Pixmap" pixmap="skin_default/icons/dish.png" zPosition="-1" position="0,0" size="130,160" alphatest="on">
251                                 <convert type="ConditionalShowHide">Blink</convert>
252                         </widget>
253                         <widget name="turnTime"   position="5,0"   size="120,20" zPosition="1" font="Regular;20" halign="right" shadowColor="black" shadowOffset="-2,-2" transparent="1" />
254                         <widget name="From"       position="5,162" size="50,17" zPosition="1" font="Regular;17" halign="left"  shadowColor="black" shadowOffset="-2,-1" transparent="1"  />
255                         <widget name="posFrom"    position="57,160" size="70,20" zPosition="1" font="Regular;20" halign="left"  shadowColor="black" shadowOffset="-2,-2" transparent="1" />
256                         <widget name="Goto"       position="5,182"  size="50,17" zPosition="1" font="Regular;17" halign="left"  shadowColor="black" shadowOffset="-2,-1" transparent="1" />
257                         <widget name="posGoto"    position="57,180" size="70,20" zPosition="1" font="Regular;20" halign="left"  shadowColor="black" shadowOffset="-2,-2" transparent="1" />
258                         <widget name="tunerName"  position="5,144"  size="90,16" zPosition="2" font="Regular;14" halign="left"  shadowColor="black" shadowOffset="-2,-1" transparent="1" />
259                         <widget name="turnSpeed"  position="75,95" size="50,16" zPosition="2" font="Regular;14" halign="right" shadowColor="black" shadowOffset="-2,-1" transparent="1" />
260                         <widget source="Frontend" render="Progress" position="5,205" size="120,10" pixmap="skin_default/bar_snr.png" zPosition="2" borderWidth="2" borderColor="#cccccc">
261                                 <convert type="FrontendInfo">SNR</convert>
262                         </widget>
263                 </screen>"""
264         def __init__(self, session):
265                 self.skin = Dishpip.skin
266                 Screen.__init__(self, session)
267                 self["Dishpixmap"] = Boolean(fixed=True, poll=1500)
268                 self["turnTime"] = Label("")
269                 self["posFrom"] = Label("")
270                 self["posGoto"] = Label("")
271                 self["From"] = Label(_("From :"))
272                 self["Goto"] = Label(_("Goto :"))
273                 self["tunerName"] = Label("")
274                 self["turnSpeed"] = Label("")
275                 self.updateRotorSatList()
276                 self.frontend = None
277                 self["Frontend"] = FrontendStatus(service_source = lambda: self.frontend, update_interval=1000)
278                 self.rotorTimer = eTimer()
279                 self.rotorTimer.timeout.get().append(self.updateRotorMovingState)
280                 self.turnTimer = eTimer()
281                 self.turnTimer.callback.append(self.turnTimerLoop)
282                 self.timeoutTimer = eTimer()
283                 self.timeoutTimer.callback.append(self.__toHide)
284                 self.rotor_pos = self.cur_orbpos = config.misc.lastrotorposition.value
285                 config.misc.lastrotorposition.addNotifier(self.RotorpositionChange)
286                 self.turn_time = self.total_time = None
287                 self.close_timeout = self.moving_timeout = self.cur_polar = 0
288                 self.__state = self.STATE_HIDDEN
289
290                 self.onShow.append(self.__onShow)
291                 self.onHide.append(self.__onHide)
292
293         def RotorpositionChange(self, configElement=None):
294                 if self.cur_orbpos != config.misc.lastrotorposition.value != INVALID_POSITION:
295                         self.rotor_pos = self.cur_orbpos = config.misc.lastrotorposition.value
296
297         def getRotorMovingState(self):
298                 return eDVBSatelliteEquipmentControl.getInstance().isRotorMoving()
299
300         def updateRotorMovingState(self):
301                 moving = self.getRotorMovingState()
302                 if moving:
303                         if self.__state == self.STATE_HIDDEN:
304                                 self.rotorTimer.stop()
305                                 self.moving_timeout = 0
306                                 if config.usage.showdish.value:
307                                         self.show()
308                                 if self.cur_orbpos != INVALID_POSITION and self.cur_orbpos != config.misc.lastrotorposition.value:
309                                         config.misc.lastrotorposition.value = self.cur_orbpos
310                                         config.misc.lastrotorposition.save()
311                 self.moving_timeout -= 1
312                 if not self.rotorTimer.isActive() and self.moving_timeout > 0:
313                         self.rotorTimer.start(1000, True)
314
315         def turnTimerLoop(self):
316                 if self.total_time:
317                         self.turn_time -= 1
318                         self["turnTime"].setText(self.FormatTurnTime(self.turn_time))
319                         self.close_timeout -=1
320                         if self.close_timeout <= 3:
321                                 self.__toHide()
322                         #elif not self.getRotorMovingState():
323                         #       self.turnTimer.stop()
324                         #       self.timeoutTimer.start(10000, True)
325                 else:
326                         if not self.getRotorMovingState():
327                                 self.turnTimer.stop()
328                                 self.timeoutTimer.start(3000, True)
329
330         def startPiPService(self, ref=None):
331                 if self.__state == self.STATE_SHOWN:
332                         self.__toHide()
333                 if ref is None:
334                         return
335                 info = eServiceCenter.getInstance().info(ref)
336                 data = info and info.getInfoObject(ref, iServiceInformation.sTransponderData)
337                 if not data or data == -1:
338                         return
339                 tuner_type = data.get("tuner_type")
340                 if tuner_type and "DVB-S" in tuner_type:
341                         cur_orbpos = data.get("orbital_position", INVALID_POSITION)
342                         if cur_orbpos in self.available_sat:
343                                 self.cur_orbpos = cur_orbpos
344                                 self.cur_polar  = data.get("polarization", 0)
345                                 self.moving_timeout = 3
346                                 if not self.rotorTimer.isActive():
347                                         self.rotorTimer.start(500, True)
348
349         def __onShow(self):
350                 self.__state = self.STATE_SHOWN
351                 prev_rotor_pos = self.rotor_pos
352                 self.rotor_pos = self.cur_orbpos
353                 self.total_time = self.getTurnTime(prev_rotor_pos, self.rotor_pos, self.cur_polar)
354                 self.turn_time = self.total_time
355                 self.close_timeout = round(self.total_time * 1.25) # aded 25%
356                 self["posFrom"].setText(self.OrbToStr(prev_rotor_pos))
357                 self["posGoto"].setText(self.OrbToStr(self.rotor_pos))
358                 self["tunerName"].setText(self.getTunerName())
359                 if self.total_time == 0:
360                         self["turnTime"].setText("")
361                         self["turnSpeed"].setText("")
362                 else:
363                         self["turnTime"].setText(self.FormatTurnTime(self.turn_time))
364                         self["turnSpeed"].setText(str(self.getTurningSpeed(self.cur_polar)) + chr(176) + _("/s"))
365                 self.turnTimer.start(1000, False)
366
367         def __onHide(self):
368                 self.__state = self.STATE_HIDDEN
369                 self.updateRotorSatList()
370
371         def setHide(self):
372                 self.__toHide()
373
374         def __toHide(self):
375                 self.rotorTimer.stop()
376                 self.turnTimer.stop()
377                 self.timeoutTimer.stop()
378                 self.close_timeout = self.moving_timeout = 0
379                 self.frontend = None
380                 if self.__state == self.STATE_SHOWN:
381                         self.hide()
382
383         def getCurrentTuner(self):
384                 if hasattr(self.session, 'pipshown') and self.session.pipshown:
385                         service = self.session.pip.pipservice
386                         if service is False or service is None:
387                                 return None
388                         self.frontend = service
389                         feinfo = service and service.frontendInfo()
390                         tuner = feinfo and feinfo.getFrontendData()
391                         if tuner is not None:
392                                 return tuner.get("tuner_number")
393                 return None