666033b159b276a4a9b9b91af33b6a6a3515951a
[vuplus_dvbapp] / lib / python / Screens / Ci.py
1 from Screen import Screen
2 from Components.ActionMap import ActionMap
3 from Components.ActionMap import NumberActionMap
4 from Components.Label import Label
5
6 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigSubList, getConfigListEntry, KEY_LEFT, KEY_RIGHT, KEY_0, ConfigNothing, ConfigPIN
7 from Components.ConfigList import ConfigList
8
9 from Components.SystemInfo import SystemInfo
10 from Tools.Directories import fileExists
11
12 from enigma import eTimer, eDVBCI_UI, eDVBCIInterfaces
13
14 MAX_NUM_CI = 4
15
16 def setCIBitrate(configElement):
17         if configElement.value == "no":
18                 eDVBCI_UI.getInstance().setClockRate(configElement.slotid, eDVBCI_UI.rateNormal)
19         else:
20                 eDVBCI_UI.getInstance().setClockRate(configElement.slotid, eDVBCI_UI.rateHigh)
21
22 def setRelevantPidsRouting(configElement):
23         fileName = "/proc/stb/tsmux/ci%d_relevant_pids_routing" % (configElement.slotid)
24         if not fileExists(fileName, 'r'):
25                 print "[CI] file not found : ", fileName
26         else:
27                 data = configElement.value
28                 if data in ("yes", "no"):
29                         fd = open(fileName, 'w')
30                         fd.write("%s" % data)
31                         fd.close()
32
33 relevantPidsRoutingChoices = None
34 def InitCiConfig():
35         config.ci = ConfigSubList()
36         for slot in range(MAX_NUM_CI):
37                 config.ci.append(ConfigSubsection())
38                 config.ci[slot].canDescrambleMultipleServices = ConfigSelection(choices = [("auto", _("Auto")), ("no", _("No")), ("yes", _("Yes"))], default = "auto")
39                 if SystemInfo["CommonInterfaceSupportsHighBitrates"]:
40                         config.ci[slot].canHandleHighBitrates = ConfigSelection(choices = [("no", _("No")), ("yes", _("Yes"))], default = "no")
41                         config.ci[slot].canHandleHighBitrates.slotid = slot
42                         config.ci[slot].canHandleHighBitrates.addNotifier(setCIBitrate)
43
44                 if SystemInfo["RelevantPidsRoutingSupport"]:
45                         global relevantPidsRoutingChoices
46                         if not relevantPidsRoutingChoices:
47                                 relevantPidsRoutingChoices = [("no", _("No")), ("yes", _("Yes"))]
48                                 default = "no"
49                                 fileName = "/proc/stb/tsmux/ci%d_relevant_pids_routing_choices"
50                                 if fileExists(fileName, 'r'):
51                                         relevantPidsRoutingChoices = []
52                                         fd = open(fileName, 'r')
53                                         data = fd.read()
54                                         data = data.split()
55                                         for x in data:
56                                                 relevantPidsRoutingChoices.append((x, _(x)))
57                                         if default not in data:
58                                                 default = data[0]
59
60                         config.ci[slot].relevantPidsRouting = ConfigSelection(choices = relevantPidsRoutingChoices, default = default)
61                         config.ci[slot].relevantPidsRouting.slotid = slot
62                         config.ci[slot].relevantPidsRouting.addNotifier(setRelevantPidsRouting)
63
64 class MMIDialog(Screen):
65         def __init__(self, session, slotid, action, handler = eDVBCI_UI.getInstance(), wait_text = _("wait for ci...") ):
66                 Screen.__init__(self, session)
67
68                 print "MMIDialog with action" + str(action)
69
70                 self.mmiclosed = False
71                 self.tag = None
72                 self.slotid = slotid
73
74                 self.timer = eTimer()
75                 self.timer.callback.append(self.keyCancel)
76
77                 #else the skins fails
78                 self["title"] = Label("")
79                 self["subtitle"] = Label("")
80                 self["bottom"] = Label("")
81                 self["entries"] = ConfigList([ ])
82
83                 self["actions"] = NumberActionMap(["SetupActions"],
84                         {
85                                 "ok": self.okbuttonClick,
86                                 "cancel": self.keyCancel,
87                                 #for PIN
88                                 "left": self.keyLeft,
89                                 "right": self.keyRight,
90                                 "1": self.keyNumberGlobal,
91                                 "2": self.keyNumberGlobal,
92                                 "3": self.keyNumberGlobal,
93                                 "4": self.keyNumberGlobal,
94                                 "5": self.keyNumberGlobal,
95                                 "6": self.keyNumberGlobal,
96                                 "7": self.keyNumberGlobal,
97                                 "8": self.keyNumberGlobal,
98                                 "9": self.keyNumberGlobal,
99                                 "0": self.keyNumberGlobal
100                         }, -1)
101
102                 self.action = action
103
104                 self.handler = handler
105                 self.wait_text = wait_text
106
107                 if action == 2:         #start MMI
108                         handler.startMMI(self.slotid)
109                         self.showWait()
110                 elif action == 3:               #mmi already there (called from infobar)
111                         self.showScreen()
112
113         def addEntry(self, list, entry):
114                 if entry[0] == "TEXT":          #handle every item (text / pin only?)
115                         list.append( (entry[1], ConfigNothing(), entry[2]) )
116                 if entry[0] == "PIN":
117                         pinlength = entry[1]
118                         if entry[3] == 1:
119                                 # masked pins:
120                                 x = ConfigPIN(0, len = pinlength, censor = "*")
121                         else:
122                                 # unmasked pins:
123                                 x = ConfigPIN(0, len = pinlength)
124                         self["subtitle"].setText(entry[2])
125                         list.append( getConfigListEntry("", x) )
126                         self["bottom"].setText(_("please press OK when ready"))
127
128         def okbuttonClick(self):
129                 self.timer.stop()
130                 if not self.tag:
131                         return
132                 if self.tag == "WAIT":
133                         print "do nothing - wait"
134                 elif self.tag == "MENU":
135                         print "answer MENU"
136                         cur = self["entries"].getCurrent()
137                         if cur:
138                                 self.handler.answerMenu(self.slotid, cur[2])
139                         else:
140                                 self.handler.answerMenu(self.slotid, 0)
141                         self.showWait()
142                 elif self.tag == "LIST":
143                         print "answer LIST"
144                         self.handler.answerMenu(self.slotid, 0)
145                         self.showWait()
146                 elif self.tag == "ENQ":
147                         cur = self["entries"].getCurrent()
148                         answer = str(cur[1].value)
149                         length = len(answer)
150                         while length < cur[1].getLength():
151                                 answer = '0'+answer
152                                 length+=1
153                         self.handler.answerEnq(self.slotid, answer)
154                         self.showWait()
155
156         def closeMmi(self):
157                 self.timer.stop()
158                 self.close(self.slotid)
159
160         def keyCancel(self):
161                 self.timer.stop()
162                 if not self.tag or self.mmiclosed:
163                         self.closeMmi()
164                 elif self.tag == "WAIT":
165                         self.handler.stopMMI(self.slotid)
166                         self.closeMmi()
167                 elif self.tag in ( "MENU", "LIST" ):
168                         print "cancel list"
169                         self.handler.answerMenu(self.slotid, 0)
170                         self.showWait()
171                 elif self.tag == "ENQ":
172                         print "cancel enq"
173                         self.handler.cancelEnq(self.slotid)
174                         self.showWait()
175                 else:
176                         print "give cancel action to ci"
177
178         def keyConfigEntry(self, key):
179                 self.timer.stop()
180                 try:
181                         self["entries"].handleKey(key)
182                 except:
183                         pass
184
185         def keyNumberGlobal(self, number):
186                 self.timer.stop()
187                 self.keyConfigEntry(KEY_0 + number)
188
189         def keyLeft(self):
190                 self.timer.stop()
191                 self.keyConfigEntry(KEY_LEFT)
192
193         def keyRight(self):
194                 self.timer.stop()
195                 self.keyConfigEntry(KEY_RIGHT)
196
197         def updateList(self, list):
198                 List = self["entries"]
199                 try:
200                         List.instance.moveSelectionTo(0)
201                 except:
202                         pass
203                 List.l.setList(list)
204
205         def showWait(self):
206                 self.tag = "WAIT"
207                 self["title"].setText("")
208                 self["subtitle"].setText("")
209                 self["bottom"].setText("")
210                 list = [ ]
211                 list.append( (self.wait_text, ConfigNothing()) )
212                 self.updateList(list)
213
214         def showScreen(self):
215                 screen = self.handler.getMMIScreen(self.slotid)
216
217                 list = [ ]
218
219                 self.timer.stop()
220                 if len(screen) > 0 and screen[0][0] == "CLOSE":
221                         timeout = screen[0][1]
222                         self.mmiclosed = True
223                         if timeout > 0:
224                                 self.timer.start(timeout*1000, True)
225                         else:
226                                 self.keyCancel()
227                 else:
228                         self.mmiclosed = False
229                         self.tag = screen[0][0]
230                         for entry in screen:
231                                 if entry[0] == "PIN":
232                                         self.addEntry(list, entry)
233                                 else:
234                                         if entry[0] == "TITLE":
235                                                 self["title"].setText(entry[1])
236                                         elif entry[0] == "SUBTITLE":
237                                                 self["subtitle"].setText(entry[1])
238                                         elif entry[0] == "BOTTOM":
239                                                 self["bottom"].setText(entry[1])
240                                         elif entry[0] == "TEXT":
241                                                 self.addEntry(list, entry)
242                         self.updateList(list)
243
244         def ciStateChanged(self):
245                 do_close = False
246                 if self.action == 0:                    #reset
247                         do_close = True
248                 if self.action == 1:                    #init
249                         do_close = True
250
251                 #module still there ?
252                 if self.handler.getState(self.slotid) != 2:
253                         do_close = True
254
255                 #mmi session still active ?
256                 if self.handler.getMMIState(self.slotid) != 1:
257                         do_close = True
258
259                 if do_close:
260                         self.closeMmi()
261                 elif self.action > 1 and self.handler.availableMMI(self.slotid) == 1:
262                         self.showScreen()
263
264                 #FIXME: check for mmi-session closed
265
266 class CiMessageHandler:
267         def __init__(self):
268                 self.session = None
269                 self.ci = { }
270                 self.dlgs = { }
271                 eDVBCI_UI.getInstance().ciStateChanged.get().append(self.ciStateChanged)
272                 SystemInfo["CommonInterface"] = eDVBCIInterfaces.getInstance().getNumOfSlots() > 0
273                 try:
274                         file = open("/proc/stb/tsmux/ci0_tsclk", "r")
275                         file.close()
276                         SystemInfo["CommonInterfaceSupportsHighBitrates"] = True
277                 except:
278                         SystemInfo["CommonInterfaceSupportsHighBitrates"] = False
279
280                 try:
281                         file = open("/proc/stb/tsmux/ci0_relevant_pids_routing", "r")
282                         file.close()
283                         SystemInfo["RelevantPidsRoutingSupport"] = True
284                 except:
285                         SystemInfo["RelevantPidsRoutingSupport"] = False
286
287         def setSession(self, session):
288                 self.session = session
289
290         def ciStateChanged(self, slot):
291                 if slot in self.ci:
292                         self.ci[slot](slot)
293                 else:
294                         if slot in self.dlgs:
295                                 self.dlgs[slot].ciStateChanged()
296                         elif eDVBCI_UI.getInstance().availableMMI(slot) == 1:
297                                 if self.session:
298                                         self.dlgs[slot] = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, 3)
299
300         def dlgClosed(self, slot):
301                 if slot in self.dlgs:
302                         del self.dlgs[slot]
303
304         def registerCIMessageHandler(self, slot, func):
305                 self.unregisterCIMessageHandler(slot)
306                 self.ci[slot] = func
307
308         def unregisterCIMessageHandler(self, slot):
309                 if slot in self.ci:
310                         del self.ci[slot]
311
312 CiHandler = CiMessageHandler()
313
314 class CiSelection(Screen):
315         def __init__(self, session):
316                 Screen.__init__(self, session)
317                 self["actions"] = ActionMap(["OkCancelActions", "CiSelectionActions"],
318                         {
319                                 "left": self.keyLeft,
320                                 "right": self.keyLeft,
321                                 "ok": self.okbuttonClick,
322                                 "cancel": self.cancel
323                         },-1)
324
325                 self.dlg = None
326                 self.state = { }
327                 self.slots = []
328                 self.HighBitrateEntry = {}
329                 self.RelevantPidsRoutingEntry = {}
330
331                 self.entryData = []
332
333                 self.list = [ ]
334                 self["entries"] = ConfigList(self.list)
335                 self["entries"].list = self.list
336                 self["entries"].l.setList(self.list)
337                 self["text"] = Label(_("Slot %d")%(1))
338                 self.onLayoutFinish.append(self.initialUpdate)
339
340         def initialUpdate(self):
341                 for slot in range(MAX_NUM_CI):
342                         state = eDVBCI_UI.getInstance().getState(slot)
343                         if state != -1:
344                                 self.slots.append(slot)
345                                 self.state[slot] = state
346                                 self.createEntries(slot)
347                                 CiHandler.registerCIMessageHandler(slot, self.ciStateChanged)
348
349                 self.updateEntries()
350
351         def selectionChanged(self):
352                 entryData = self.entryData[self["entries"].getCurrentIndex()]
353                 self["text"].setText(_("Slot %d")%(entryData[1] + 1))
354
355         def keyConfigEntry(self, key):
356                 current = self["entries"].getCurrent()
357                 try:
358                         self["entries"].handleKey(key)
359                         current[1].save()
360                 except:
361                         pass
362
363         def keyLeft(self):
364                 self.keyConfigEntry(KEY_LEFT)
365
366         def keyRight(self):
367                 self.keyConfigEntry(KEY_RIGHT)
368
369         def createEntries(self, slot):
370                 if SystemInfo["CommonInterfaceSupportsHighBitrates"]:
371                         self.HighBitrateEntry[slot] = getConfigListEntry(_("High bitrate support"), config.ci[slot].canHandleHighBitrates)
372                 if SystemInfo["RelevantPidsRoutingSupport"]:
373                         self.RelevantPidsRoutingEntry[slot] = getConfigListEntry(_("Relevant PIDs Routing"), config.ci[slot].relevantPidsRouting)
374
375         def addToList(self, data, action, slotid):
376                 self.list.append(data)
377                 self.entryData.append((action, slotid))
378
379         def updateEntries(self):
380                 self.list = []
381                 self.entryData = []
382                 for slot in self.slots:
383                         self.addToList((_("Reset"), ConfigNothing()), 0, slot)
384                         self.addToList((_("Init"), ConfigNothing()), 1, slot)
385
386                         if self.state[slot] == 0:                       #no module
387                                 self.addToList((_("no module found"), ConfigNothing()), 2, slot)
388                         elif self.state[slot] == 1:             #module in init
389                                 self.addToList((_("init module"), ConfigNothing()), 2, slot)
390                         elif self.state[slot] == 2:             #module ready
391                                 #get appname
392                                 appname = eDVBCI_UI.getInstance().getAppName(slot)
393                                 self.addToList((appname, ConfigNothing()), 2, slot)
394
395                         self.addToList(getConfigListEntry(_("Multiple service support"), config.ci[slot].canDescrambleMultipleServices), -1, slot)
396
397                         if SystemInfo["CommonInterfaceSupportsHighBitrates"]:
398                                 self.addToList(self.HighBitrateEntry[slot], -1, slot)
399                         if SystemInfo["RelevantPidsRoutingSupport"]:
400                                 self.addToList(self.RelevantPidsRoutingEntry[slot], -1, slot)
401
402                 self["entries"].list = self.list
403                 self["entries"].l.setList(self.list)
404                 if self.selectionChanged not in self["entries"].onSelectionChanged:
405                         self["entries"].onSelectionChanged.append(self.selectionChanged)
406
407         def ciStateChanged(self, slot):
408                 if self.dlg:
409                         self.dlg.ciStateChanged()
410                 else:
411                         state = eDVBCI_UI.getInstance().getState(slot)
412                         if self.state[slot] != state:
413                                 #print "something happens"
414                                 self.state[slot] = state
415                                 self.updateEntries()
416
417         def dlgClosed(self, slot):
418                 self.dlg = None
419
420         def okbuttonClick(self):
421                 cur = self["entries"].getCurrent()
422                 if cur:
423                         idx = self["entries"].getCurrentIndex()
424                         entryData = self.entryData[idx]
425                         action = entryData[0]
426                         slot = entryData[1]
427                         if action == 0:         #reset
428                                 eDVBCI_UI.getInstance().setReset(slot)
429                         elif action == 1:               #init
430                                 eDVBCI_UI.getInstance().setInit(slot)
431                         elif action == 2 and self.state[slot] == 2:
432                                 self.dlg = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, action)
433
434         def cancel(self):
435                 for slot in range(MAX_NUM_CI):
436                         state = eDVBCI_UI.getInstance().getState(slot)
437                         if state != -1:
438                                 CiHandler.unregisterCIMessageHandler(slot)
439                 self.close()