[videomode] enabled Scart for soloSE
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / Videomode / VideoHardware.py
1 from Components.config import config, ConfigSubDict, ConfigSelection
2 from Tools.CList import CList
3 from Tools.HardwareInfo import HardwareInfo
4
5 # VideoHardware is the interface to /proc/stb/video.
6 class VideoHardware:
7         is_init = True
8
9         modes = { # a list of modes for available port
10                 "Scart" : ["PAL", "NTSC", "Multi"],
11                 "YPbPr" : ["720p", "1080i", "576p", "480p", "576i", "480i"],
12                 "DVI"   : ["720p", "1080i", "576p", "480p", "576i", "480i"],
13                 "DVI-PC": ["PC"]
14         }
15         rates = { # list of rates for available mode
16                 "PAL":   { "50Hz" : {50: "pal"},
17                                    "60Hz" : {60: "pal60"},
18                                    "multi": {50: "pal", 60: "pal60"}
19                 },
20                 "NTSC":  { "60Hz" : {60: "ntsc"} },
21                 "Multi": { "multi": {50: "pal", 60: "ntsc"} },
22                 "480i":  { "60Hz" : {60: "480i"} },
23                 "576i":  { "50Hz" : {50: "576i"} },
24                 "480p":  { "60Hz" : {60: "480p"} },
25                 "576p":  { "50Hz" : {50: "576p"} },
26                 "720p":  {
27                         "50Hz" : {50: "720p50"},
28                         "60Hz" : {60: "720p"},
29                         "multi": {50: "720p50", 60: "720p"}
30                 },
31                 "1080i": {
32                         "50Hz" : {50: "1080i50"},
33                         "60Hz" : {60: "1080i"},
34                         "multi": {50: "1080i50", 60: "1080i"}
35                 },
36                 "1080p": {
37                         "50Hz" : {50: "1080p50"},
38                         "60Hz" : {60: "1080p"},
39                         "multi": {50: "1080p50", 60: "1080p"}
40                 },
41                 "PC": {
42                         "1024x768": {60: "1024x768"},
43                         "800x600" : {60: "800x600"},
44                         "720x480" : {60: "720x480"},
45                         "720x576" : {60: "720x576"},
46                         "1280x720": {60: "1280x720"},
47                         "1280x720 multi": {50: "1280x720_50", 60: "1280x720"},
48                         "1920x1080": {60: "1920x1080"},
49                         "1920x1080 multi": {50: "1920x1080", 60: "1920x1080_50"},
50                         "1280x1024": {60: "1280x1024"},
51                         "1366x768": {60: "1366x768"},
52                         "1366x768 multi": {50: "1366x768", 60: "1366x768_50"},
53                         "1280x768": {60: "1280x768"},
54                         "640x480" : {60: "640x480"}
55                 }
56         }
57
58         widescreen_modes = set(["720p", "1080i", "1080p"])
59         hdmi_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose"])
60         hdmi_pc_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose"])
61         noscart_hw_types = set()
62         noypbpr_hw_types = set(["solose"])
63
64         def getDeviceName(self):
65                 device_name = "unknown"
66                 try:
67                         file = open("/proc/stb/info/vumodel", "r")
68                         device_name = file.readline().strip()
69                         file.close()
70                 except IOError:
71                         from Tools.HardwareInfo import HardwareInfo
72                         device_name = HardwareInfo.get_device_name()
73
74                 return device_name
75
76         def isVumodel(self, hw_type):
77                 return hw_type in set(["bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose"])
78
79         # re-define AVSwitch.getOutputAspect
80         def getOutputAspect(self):
81                 ret = (16,9)
82                 port = config.av.videoport.value
83                 if port not in config.av.videomode:
84                         print "current port is not available. force 16:9"
85                 else:
86                         mode = config.av.videomode[port].value
87                         force_wide = self.isWidescreenMode(mode)
88                         valstr = config.av.aspect.value
89
90                         if force_wide:
91                                 pass
92                         elif valstr == "16_10":
93                                 ret = (16,10)
94                         elif valstr == "auto":
95                                 try:
96                                         aspect_str = open("/proc/stb/vmpeg/0/aspect", "r").read()
97                                         if aspect_str == "1": # 4:3
98                                                 ret = (4,3)
99                                 except IOError:
100                                         pass
101                         elif valstr == "4_3":
102                                 ret = (4,3)
103                 return ret
104
105         def __init__(self):
106                 self.last_modes_preferred = [ ]
107                 self.on_hotplug = CList()
108
109                 self.readAvailableModes()
110
111                 if self.modes.has_key("DVI-PC") and not self.getModeList("DVI-PC"):
112                         print "remove DVI-PC because it does not exist."
113                         del self.modes["DVI-PC"]
114
115                 if self.isNoScart(self.getDeviceName()):
116                         if self.modes.has_key("Scart"):
117                                 print "remove Scart because it does not exist."
118                                 del self.modes["Scart"]
119
120                 if self.isNoYPbPr(self.getDeviceName()):
121                         if self.modes.has_key("YPbPr"):
122                                 print "remove YPbPr because it does not exist."
123                                 del self.modes["YPbPr"]
124
125                 self.createConfig()
126
127                 self.readPreferredModes()
128
129                 # re-define AVSwitch components
130                 from Components.AVSwitch import AVSwitch
131                 config.av.aspectratio.notifiers = [ ]
132                 config.av.tvsystem.notifiers = [ ]
133                 config.av.wss.notifiers = [ ]
134                 AVSwitch.getOutputAspect = self.getOutputAspect
135
136                 config.av.aspect.addNotifier(self.changedAspect)
137                 config.av.wss.addNotifier(self.changedAspect)
138                 config.av.policy_169.addNotifier(self.changedAspect)
139                 config.av.policy_43.addNotifier(self.changedAspect)
140
141                 # addNotifiers for port, mode, rate
142                 config.av.videoport.addNotifier(self.changedVideomode)
143                 for port in self.getPortList():
144                         config.av.videomode[port].addNotifier(self.changedVideomode)
145                         for mode in self.getModeList(port):
146                                 config.av.videorate[mode[0]].addNotifier(self.changedVideomode)
147
148                 self.is_init = False
149
150         def readAvailableModes(self):
151                 try:
152                         modes = open("/proc/stb/video/videomode_choices").read()[:-1]
153                         self.modes_available = modes.split(' ')
154                 except IOError:
155                         print "failed to read video_choices."
156                         self.modes_available = [ ]
157
158         def readPreferredModes(self):
159                 try:
160                         modes = open("/proc/stb/video/videomode_preferred").read()[:-1]
161                         self.modes_preferred = modes.split(' ')
162                 except IOError:
163                         print "failed to read video_preferred."
164                         self.modes_preferred = self.modes_available
165
166                 if self.modes_preferred != self.last_modes_preferred:
167                         self.last_modes_preferred = self.modes_preferred
168                         print "hotplug on DVI"
169                         self.on_hotplug("DVI") # must be DVI
170
171         # check if HDMI is available
172         def isHDMIAvailable(self, hw_type):
173                 return hw_type in self.hdmi_hw_types
174
175         # check if HDMI-PC is available
176         def isHDMI_PCAvailable(self, hw_type):
177                 return hw_type in self.hdmi_pc_hw_types
178
179         # check if mode is always widescreen
180         def isWidescreenMode(self, mode):
181                 return mode in self.widescreen_modes
182
183         # check if Scart is not available
184         def isNoScart(self, hw_type):
185                 return hw_type in self.noscart_hw_types
186
187         # check if YPbPr is not available
188         def isNoYPbPr(self, hw_type):
189                 return hw_type in self.noypbpr_hw_types
190
191         # check if rate is available for mode
192         def isModeAvailable(self, port, mode, rate):
193                 rate = self.rates[mode][rate]
194                 for mode in rate.values():
195                         if mode not in self.modes_available:
196                                 return False
197
198                 return True
199
200         # check isModeAvailable in this port
201         def isPortAvailable(self, port):
202                 for mode in self.getModeList(port):
203                         if len(self.getRateList(port, mode[0])):
204                                 return True
205
206                 return False
207
208         # get a list of all available port
209         def getPortList(self):
210                 return [port for port in self.modes if self.isPortAvailable(port)]
211
212         # get a list of all available mode for a given port
213         def getModeList(self, port):
214                 modelist = [ ]
215                 for mode in self.modes[port]:
216                         rates = self.getRateList(port, mode)
217
218                         if len(rates):
219                                 modelist.append( (mode, rates))
220
221                 return modelist
222
223         # get a list of all available rate for a given port, mode
224         def getRateList(self, port, mode):
225                 return [rate for rate in self.rates[mode] if self.isModeAvailable(port, mode, rate)]
226
227         def createConfig(self):
228                 config.av.videomode = ConfigSubDict()
229                 config.av.videorate = ConfigSubDict()
230
231                 hw_type = self.getDeviceName()
232                 # vu+ support 1080p
233                 if self.isVumodel(hw_type):
234                         self.modes["DVI"].insert(self.modes["DVI"].index("1080i")+1, "1080p")
235
236                 portlist = [ ]
237                 port_choices = self.getPortList()
238
239                 for port in port_choices:
240                         desc = port
241                         if desc == 'DVI' and self.isHDMIAvailable(hw_type):
242                                 desc = 'HDMI'
243                         if desc == 'DVI-PC' and self.isHDMI_PCAvailable(hw_type):
244                                 desc = 'HDMI-PC'
245                         portlist.append( (port, desc))
246
247                         # create list of available modes
248                         modelist = [ ]
249                         mode_choices = self.getModeList(port)
250
251                         for mode in mode_choices:
252                                 modelist.append( (mode[0], mode[0]))
253
254                                 # create list of available rates
255                                 ratelist = [ ]
256                                 rate_choices = self.getRateList(port, mode[0])
257
258                                 for rate in rate_choices:
259                                         ratelist.append( (rate, rate))
260
261                                 config.av.videorate[mode[0]] = ConfigSelection(choices = ratelist)
262                         config.av.videomode[port] = ConfigSelection(choices = modelist)
263                 config.av.videoport = ConfigSelection(choices = portlist)
264
265         def changedVideomode(self, configElement):
266                 if self.is_init:
267                         return
268
269                 self.setConfiguredMode()
270
271         def setConfiguredMode(self):
272                 port = config.av.videoport.value
273                 mode = config.av.videomode[port].value
274                 rate = config.av.videorate[mode].value
275
276                 self.setVideomode(port, mode, rate)
277
278         def setVideomode(self, port, mode, rate):
279                 if port is None or port not in config.av.videomode:
280                         print "current port not available. couldn't set videomode"
281                         return
282
283                 if mode not in config.av.videorate:
284                         print "current mode not available. couldn't set videomode"
285                         return
286
287                 if mode is None:
288                         modelist = self.getModeList(port)
289                         mode = modelist[0][0]
290
291                         ratelist = self.getRateList(port, mode)
292                         rate = ratelist[0]
293
294                 if rate is None:
295                         ratelist = self.getRateList(port, mode)
296                         rate = ratelist[0]
297
298                 print "set Videomode", port, mode, rate
299
300                 modes = self.rates[mode][rate]
301                 mode_50 = modes.get(50)
302                 mode_60 = modes.get(60)
303                 if mode_50 is None:
304                         mode_50 = mode_60
305                 if mode_60 is None:
306                         mode_60 = mode_50
307
308                 if (mode_50 != mode_60):
309                         try:
310                                 open("/proc/stb/video/videomode_50hz", "w").write(mode_50)
311                                 open("/proc/stb/video/videomode_60hz", "w").write(mode_60)
312                         except IOError:
313                                 print "cannot open /proc/stb/vide/videomode_50hz or videomode_60hz"
314
315                         # Too slow moving to Scart/multi in modeSelectionMoved
316                         #try:
317                         #       open("/proc/stb/video/videomode_50hz", "w").write(mode_60)
318                         #except IOError:
319                         #       print "cannot open /proc/stb/vide/videomode_60Hz"
320
321                 else:
322                         try:
323                                 open("/proc/stb/video/videomode", "w").write(mode_50)
324                         except IOError:
325                                 print "cannot open /proc/stb/vide/videomode"
326
327                 self.changedAspect(None)
328
329         def changedAspect(self, configElement):
330                 if self.is_init:
331                         return
332                 # config.av.aspect:
333                 #       4:3                     use policy_169
334                 #       16:9, 16:10     use policy_43
335                 #       auto            always "bestfit"
336                 # config.av.policy_169:
337                 #       letterbox       use letterbox
338                 #       panscan         use panscan
339                 #       scale           use bestfit
340                 # config.av.policy_43:
341                 #       pillarbox       use panscan
342                 #       pansca          use letterbox ("panscan" is just a bad term, it is inverse-panscan)
343                 #       nonlinear       use nonlinear
344                 #       scale           use bestfit
345
346                 port = config.av.videoport.value
347                 if port not in config.av.videomode:
348                         print "current port not available. couldn't set aspect"
349                         return
350
351                 mode = config.av.videomode[port].value
352                 force_wide = self.isWidescreenMode(mode)
353                 valstr = config.av.aspect.value
354
355                 policy2 = "policy" # use main policy
356
357                 if force_wide or valstr == "16_9" or valstr == "16_10":
358                         if force_wide or valstr == "16_9":
359                                 aspect = "16:9"
360                         elif valstr == "16_10":
361                                 aspect = "16:10"
362
363                         policy = {"pillarbox": "panscan", "panscan": "letterbox", "nonlinear": "nonlinear", "scale": "bestfit"}[config.av.policy_43.value]
364                         policy2 = {"letterbox": "letterbox", "panscan": "panscan", "scale": "bestfit"}[config.av.policy_169.value]
365                 elif valstr == "auto":
366                         aspect = "any"
367                         policy = "bestfit"
368                 else:
369                         aspect = "4:3"
370                         policy = {"letterbox": "letterbox", "panscan": "panscan", "scale": "bestfit"}[config.av.policy_169.value]
371
372                 if not config.av.wss.value:
373                         wss = "auto(4:3_off)"
374                 else:
375                         wss = "auto"
376
377                 self.setAspect(aspect, policy, policy2, wss)
378
379         def setAspect(self, aspect, policy, policy2, wss):
380                 print "set aspect, policy, policy2, wss", aspect, policy, policy2, wss
381
382                 open("/proc/stb/video/aspect", "w").write(aspect)
383                 open("/proc/stb/video/policy", "w").write(policy)
384                 open("/proc/stb/denc/0/wss", "w").write(wss)
385                 try:
386                         open("/proc/stb/video/policy2", "w").write(policy2)
387                 except IOError:
388                         pass
389
390         def isPortUsed(self, port):
391                 if port == "DVI":
392                         self.readPreferredModes()
393                         return len(self.modes_preferred) != 0
394                 else:
395                         return True
396
397         def saveVideomode(self, port, mode, rate):
398                 print "save Videomode", port, mode, rate
399                 config.av.videoport.value = port
400                 config.av.videoport.save()
401                 if port in config.av.videomode:
402                         config.av.videomode[port].value = mode
403                         config.av.videomode[port].save()
404                 if mode in config.av.videorate:
405                         config.av.videorate[mode].value = rate
406                         config.av.videorate[mode].save()
407
408         # for dependency
409         def setMode(self, port, mode, rate):
410                 self.setVideomode(port, mode, rate)
411
412         def saveMode(self, port, mode, rate):
413                 self.saveVideomode(port, mode, rate)
414
415         def updateAspect(self, configElement):
416                 self.changedAspect(configElement)
417
418 video_hw = VideoHardware()
419 video_hw.setConfiguredMode()
420