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