fix wss, slowblank, standby without scartswitch (requires new drivers)
[enigma2.git] / lib / python / Plugins / SystemPlugins / Videomode / VideoHardware.py
1 from Screens.Screen import Screen
2 from Plugins.Plugin import PluginDescriptor
3
4 from enigma import eTimer
5
6 from Components.ActionMap import ActionMap
7 from Components.Label import Label
8 from Components.Pixmap import Pixmap
9 from Screens.MessageBox import MessageBox
10 from Screens.Setup import SetupSummary
11 from Components.ConfigList import ConfigListScreen
12 from Components.config import getConfigListEntry, config, ConfigSelection, ConfigSubDict, ConfigYesNo
13
14 from Tools.CList import CList
15
16 # The "VideoHardware" is the interface to /proc/stb/video.
17 # It generates hotplug events, and gives you the list of 
18 # available and preferred modes, as well as handling the currently
19 # selected mode. No other strict checking is done.
20 class VideoHardware:
21         rates = { } # high-level, use selectable modes.
22
23         modes = { }  # a list of (high-level) modes for a certain port.
24
25         rates["PAL"] =                  { "50Hz":               { 50: "pal", 60: "pal"},
26                                                                                                 "60Hz":         { 50: "pal60", 60: "pal60"},
27                                                                                                 "multi":        { 50: "pal", 60: "pal60"} }
28         rates["NTSC"] =                 { "60Hz":       { 50: "ntsc", 60: "ntsc"} }
29         rates["Multi"] =                { "multi":      { 50: "pal", 60: "ntsc"} }
30         rates["720p"] =                 {       "50Hz":         { 50: "720p50", 60: "720p50"},
31                                                                                                 "60Hz":         { 50: "720p", 60: "720p"},
32                                                                                                 "multi":        { 50: "720p50", 60: "720p"} }
33         rates["1080i"] =                { "50Hz":               { 50: "1080i50", 60: "1080i50"},
34                                                                                                 "60Hz":         { 50: "1080i", 60: "1080i"},
35                                                                                                 "multi":        { 50: "1080i50", 60: "1080i"} }
36         rates["PC"] = { 
37                 "1024x768": { 60: "1024x768"}, # not possible on DM7025
38                 "800x600" : { 60: "800x600"},  # also not possible
39                 "720x480" : { 60: "720x480"},
40                 "720x576" : { 60: "720x576"},
41                 "1280x720": { 60: "1280x720"},
42                 "1280x720 multi": { 50: "1280x720_50", 60: "1280x720"},
43                 "1920x1080": { 60: "1920x1080"},
44                 "1920x1080 multi": { 50: "1920x1080", 60: "1920x1080_50"},
45                 "1280x1024" : { 60: "1280x1024"},
46                 "1366x768" : { 60: "1366x768"},
47                 "1366x768 multi" : { 50: "1366x768", 60: "1366x768_50"},
48                 "1280x768": { 60: "1280x768"},
49                 "640x480" : { 60: "640x480"} 
50         }
51
52         modes["Scart"] = ["PAL", "NTSC", "Multi"]
53         modes["YPbPr"] = ["720p", "1080i"]
54         modes["DVI"] = ["720p", "1080i", "PC"]
55
56         widescreen_modes = set(["720p", "1080i"])
57
58         def __init__(self):
59                 self.last_modes_preferred =  [ ]
60                 self.on_hotplug = CList()
61                 self.standby = False
62
63                 self.readAvailableModes()
64
65                 self.createConfig()
66 #               self.on_hotplug.append(self.createConfig)
67
68                 self.readPreferredModes()
69
70                 # take over old AVSwitch component :)
71                 from Components.AVSwitch import AVSwitch
72 #               config.av.colorformat.notifiers = [ ] 
73                 config.av.aspectratio.notifiers = [ ]
74                 config.av.tvsystem.notifiers = [ ]
75                 config.av.wss.notifiers = [ ]
76                 AVSwitch.setInput = self.AVSwitchSetInput
77
78                 config.av.aspect.addNotifier(self.updateAspect)
79                 config.av.wss.addNotifier(self.updateAspect)
80                 config.av.policy_169.addNotifier(self.updateAspect)
81                 config.av.policy_43.addNotifier(self.updateAspect)
82
83                 # until we have the hotplug poll socket
84 #               self.timer = eTimer()
85 #               self.timer.callback.append(self.readPreferredModes)
86 #               self.timer.start(1000)
87
88
89         def AVSwitchSetInput(self, mode):
90                 self.standby = mode == "SCART"
91                 self.updateStandby()
92
93         def readAvailableModes(self):
94                 try:
95                         modes = open("/proc/stb/video/videomode_choices").read()[:-1]
96                 except IOError:
97                         print "couldn't read available videomodes."
98                         self.modes_available = [ ]
99                         return
100                 self.modes_available = modes.split(' ')
101
102         def readPreferredModes(self):
103                 try:
104                         modes = open("/proc/stb/video/videomode_preferred").read()[:-1]
105                         self.modes_preferred = modes.split(' ')
106                 except IOError:
107                         print "reading preferred modes failed, using all modes"
108                         self.modes_preferred = self.modes_available
109
110                 if self.modes_preferred != self.last_modes_preferred:
111                         self.last_modes_preferred = self.modes_preferred
112                         print "hotplug on dvi"
113                         self.on_hotplug("DVI") # must be DVI
114
115         # check if a high-level mode with a given rate is available.
116         def isModeAvailable(self, port, mode, rate):
117                 rate = self.rates[mode][rate]
118                 for mode in rate.values():
119                         # DVI modes must be in "modes_preferred"
120 #                       if port == "DVI":
121 #                               if mode not in self.modes_preferred and not config.av.edid_override.value:
122 #                                       print "no, not preferred"
123 #                                       return False
124                         if mode not in self.modes_available:
125                                 return False
126                 return True
127
128         def isWidescreenMode(self, port, mode):
129                 return mode in self.widescreen_modes
130
131         def setMode(self, port, mode, rate, force = None):
132                 print "setMode - port:", port, "mode:", mode, "rate:", rate
133                 # we can ignore "port"
134                 self.current_mode = mode
135                 modes = self.rates[mode][rate]
136
137                 mode_50 = modes.get(50)
138                 mode_60 = modes.get(60)
139                 if mode_50 is None or force == 60:
140                         mode_50 = mode_60
141                 if mode_60 is None or force == 50: 
142                         mode_60 = mode_50
143
144                 try:
145                         open("/proc/stb/video/videomode_50hz", "w").write(mode_50)
146                         open("/proc/stb/video/videomode_60hz", "w").write(mode_60)
147                 except IOError:
148                         try:
149                                 # fallback if no possibility to setup 50/60 hz mode
150                                 open("/proc/stb/video/videomode", "w").write(mode_50)
151                         except IOError:
152                                 print "setting videomode failed."
153
154                 try:
155                         open("/etc/videomode", "w").write(mode_50) # use 50Hz mode (if available) for booting
156                 except IOError:
157                         print "writing initial videomode to /etc/videomode failed."
158
159                 self.updateAspect(None)
160
161         def saveMode(self, port, mode, rate):
162                 config.av.videoport.value = port
163                 config.av.videomode[port].value = mode
164                 config.av.videorate[mode].value = rate
165
166         def isPortAvailable(self, port):
167                 # fixme
168                 return True
169
170         def isPortUsed(self, port):
171                 if port == "DVI":
172                         self.readPreferredModes()
173                         return len(self.modes_preferred) != 0
174                 else:
175                         return True
176
177         def getPortList(self):
178                 return [port for port in self.modes if self.isPortAvailable(port)]
179
180         # get a list with all modes, with all rates, for a given port.
181         def getModeList(self, port):
182                 print "getModeList for port", port
183                 res = [ ]
184                 for mode in self.modes[port]:
185                         # list all rates which are completely valid
186                         rates = [rate for rate in self.rates[mode] if self.isModeAvailable(port, mode, rate)]
187
188                         # if at least one rate is ok, add this mode
189                         if len(rates):
190                                 res.append( (mode, rates) )
191                 return res
192
193         def createConfig(self, *args):
194                 # create list of output ports
195                 portlist = self.getPortList()
196
197                 # create list of available modes
198                 config.av.videoport = ConfigSelection(choices = [(port, _(port)) for port in portlist])
199                 config.av.videomode = ConfigSubDict()
200                 config.av.videorate = ConfigSubDict()
201
202                 for port in portlist:
203                         modes = self.getModeList(port)
204                         if len(modes):
205                                 config.av.videomode[port] = ConfigSelection(choices = [mode for (mode, rates) in modes])
206                         for (mode, rates) in modes:
207                                 config.av.videorate[mode] = ConfigSelection(choices = rates)
208
209         def setConfiguredMode(self):
210                 port = config.av.videoport.value
211                 if port not in config.av.videomode:
212                         print "current port not available, not setting videomode"
213                         return
214
215                 mode = config.av.videomode[port].value
216
217                 if mode not in config.av.videorate:
218                         print "current mode not available, not setting videomode"
219                         return
220
221                 rate = config.av.videorate[mode].value
222                 self.setMode(port, mode, rate)
223
224         def updateAspect(self, cfgelement):
225                 # determine aspect = {any,4:3,16:9,16:10}
226                 # determine policy = {bestfit,letterbox,panscan,nonlinear}
227
228                 # based on;
229                 #   config.av.videoport.value: current video output device
230                 #     Scart: 
231                 #   config.av.aspect:
232                 #     4_3:            use policy_169
233                 #     16_9,16_10:     use policy_43
234                 #     auto            always "bestfit"
235                 #   config.av.policy_169
236                 #     letterbox       use letterbox
237                 #     panscan         use panscan
238                 #     scale           use bestfit
239                 #   config.av.policy_43
240                 #     pillarbox       use panscan
241                 #     panscan         use letterbox  ("panscan" is just a bad term, it's inverse-panscan)
242                 #     nonlinear       use nonlinear
243                 #     scale           use bestfit
244
245                 port = config.av.videoport.value
246                 if port not in config.av.videomode:
247                         print "current port not available, not setting videomode"
248                         return
249                 mode = config.av.videomode[port].value
250
251                 force_widescreen = self.isWidescreenMode(port, mode)
252
253                 is_widescreen = force_widescreen or config.av.aspect.value in ["16_9", "16_10"]
254                 is_auto = config.av.aspect.value == "auto"
255
256                 if is_widescreen:
257                         if force_widescreen:
258                                 aspect = "16:9"
259                         else:
260                                 aspect = {"16_9": "16:9", "16_10": "16:10"}[config.av.aspect.value]
261                         policy = {"pillarbox": "panscan", "panscan": "letterbox", "nonlinear": "nonlinear", "scale": "bestfit"}[config.av.policy_43.value]
262                 elif is_auto:
263                         aspect = "any"
264                         policy = "bestfit"
265                 else:
266                         aspect = "4:3"
267                         policy = {"letterbox": "letterbox", "panscan": "panscan", "scale": "bestfit"}[config.av.policy_169.value]
268
269                 if not config.av.wss.value:
270                         wss = "auto(4:3_off)"
271                 else:
272                         wss = "auto"
273
274                 print "-> setting aspect, policy, wss", aspect, policy, wss
275                 open("/proc/stb/video/aspect", "w").write(aspect)
276                 open("/proc/stb/video/policy", "w").write(policy)
277                 open("/proc/stb/denc/0/wss", "w").write(wss)
278                 self.updateSlowblank()
279
280         def updateSlowblank(self):
281                 if self.standby:
282                         from Components.SystemInfo import SystemInfo
283                         if SystemInfo["ScartSwitch"]:
284                                 mode = "scart"
285                                 sb = "vcr"
286                         else:
287                                 mode = "off"
288                                 sb = "0"
289                 else:
290                         mode = "encoder"
291                         sb = "auto"
292
293                 open("/proc/stb/avs/0/sb", "w").write(sb)
294                 open("/proc/stb/avs/0/input", "w").write(mode)
295
296         def updateStandby(self):
297                 self.updateSlowblank()
298
299 config.av.edid_override = ConfigYesNo(default = False)
300 video_hw = VideoHardware()
301 video_hw.setConfiguredMode()