OLD | NEW |
| (Empty) |
1 #!/usr/bin/python | |
2 # | |
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 | |
7 # DESCRIPTION : | |
8 # | |
9 # Intended for use during manufacturing to validate that developer | |
10 # switch and recovery button function properly. Run normally, test | |
11 # will display an D-housing image identifying where recovery button and | |
12 # developer switch are located. It will highlight when recovery has | |
13 # been pressed and released. It will highlight when developer switch | |
14 # has been switched & unswitched. If successful, a brief 'PASS' message | |
15 # will be displayed and the test will terminate. If not, the test will | |
16 # fail with an 'ERROR' message that is displayed forever (unless the | |
17 # 'hwqual' argument is passed in). | |
18 | |
19 import cairo | |
20 import gobject | |
21 import gtk | |
22 import sys | |
23 import time | |
24 import os | |
25 import math | |
26 | |
27 class DevRecTest(): | |
28 | |
29 gpio_info = { | |
30 'developer' : {'type' : 'switch', | |
31 'cx' : 355, | |
32 'cy' : 175, | |
33 'size' : 30, | |
34 'arrow' : {'x' : 305, | |
35 'y' : 175, | |
36 'width' : 15, | |
37 'length' : 100, | |
38 # in degrees starts as rt arrow | |
39 'direction' : 0, | |
40 }, | |
41 }, | |
42 'recovery' : {'type' : 'button', | |
43 'cx' : 635, | |
44 'cy' : 425, | |
45 'size' : 30, | |
46 'arrow' : {'x' : 580, | |
47 'y' : 425, | |
48 'width' : 15, | |
49 'length' : 100, | |
50 'direction' : 270, | |
51 } | |
52 }, | |
53 } | |
54 | |
55 # How long DevRecTest allows in seconds until failing | |
56 timeout = 20 | |
57 | |
58 # How long to display the success message in seconds before exit. | |
59 pass_msg_timeout = 2 | |
60 | |
61 # Background color and alpha for the final result message. | |
62 bg_rgba_fail = (0.7, 0, 0, 0.9) | |
63 bg_rgba_pass = ( 0, 0.7, 0, 0.9) | |
64 | |
65 rgba_state = [(0.0, 1.0, 0.0, 0.9), | |
66 (0.9, 0.9, 0.0, 0.6), | |
67 (0.9, 0.0, 0.0, 0.6)] | |
68 | |
69 def __init__(self, autodir, devrec_image): | |
70 self._devrec_image = devrec_image | |
71 self._successful = set() | |
72 self._deadline = None | |
73 self._success = None | |
74 self.gpios = devrec_gpio(autodir) | |
75 self.gpios.cfg() | |
76 | |
77 def show_arrow(self, context, cx, cy, headx, heady, awidth, length, | |
78 degrees): | |
79 | |
80 '''Draw a simple arrow in given context. | |
81 ''' | |
82 | |
83 context.save() | |
84 | |
85 # rotation transform | |
86 matrix = cairo.Matrix(1, 0, 0, 1, 0, 0) | |
87 context.set_source_rgba(0, 0, 0, 1) | |
88 cairo.Matrix.translate(matrix, cx, cy) | |
89 cairo.Matrix.rotate(matrix, math.radians(degrees)) | |
90 cairo.Matrix.translate(matrix, -cx, -cy) | |
91 context.transform(matrix) | |
92 | |
93 # right arrow default | |
94 context.set_line_width(5) | |
95 context.move_to(headx, heady) | |
96 context.rel_line_to(-awidth, -awidth/2.0) | |
97 context.rel_line_to(0, awidth) | |
98 context.rel_line_to(awidth, -awidth/2.0) | |
99 context.fill_preserve() | |
100 context.rel_line_to(-length, 0) | |
101 context.stroke_preserve() | |
102 context.set_source_rgba(0, 0, 0, 0.5) | |
103 context.stroke_preserve() | |
104 context.restore() | |
105 | |
106 def start_countdown(self, duration): | |
107 self._deadline = int(time.time()) + duration | |
108 | |
109 def request_action(self, widget, context, name): | |
110 '''Determine action required by gpio state and show | |
111 ''' | |
112 | |
113 gpio_default = self.gpios.table[name][1] | |
114 gpio_state = self.gpios.table[name][2] | |
115 gpio_val = self.gpios.gpio_read(name) | |
116 | |
117 # state transitions based on current value | |
118 if (gpio_state == 2) and (gpio_val != gpio_default): | |
119 gpio_state-=1 | |
120 # refresh countdown | |
121 self.start_countdown(self.timeout) | |
122 elif (gpio_state == 1) and (gpio_val == gpio_default): | |
123 gpio_state-=1 | |
124 self._successful.add(name) | |
125 if self.gpio_info.__len__() is self._successful.__len__(): | |
126 self._success = True | |
127 self.start_countdown(self.pass_msg_timeout) | |
128 | |
129 # store state change | |
130 self.gpios.table[name][2] = gpio_state | |
131 | |
132 widget_width, widget_height = widget.get_size_request() | |
133 context.save() | |
134 ginfo = self.gpio_info[name] | |
135 | |
136 context.set_source_rgba(0, 0, 0, 1) | |
137 | |
138 if (ginfo['type'] == 'button'): | |
139 text = ['Done', 'Release', 'Press'] | |
140 context.arc(ginfo['cx'], ginfo['cy'], ginfo['size'], | |
141 0, math.radians(360)) | |
142 context.stroke() | |
143 context.arc(ginfo['cx'], ginfo['cy'], ginfo['size'], | |
144 0, math.radians(360)) | |
145 elif (ginfo['type'] == 'switch'): | |
146 text = ['Done', 'Restore', 'Move'] | |
147 # two rects one outline of switch body the other | |
148 # representing the position | |
149 rect_x = ginfo['cx'] - ginfo['size'] | |
150 rect_y = ginfo['cy'] - ginfo['size'] / 2.0 | |
151 context.rectangle(rect_x, rect_y, ginfo['size'] * 2, | |
152 ginfo['size']) | |
153 | |
154 context.stroke() | |
155 | |
156 if gpio_state == 1: | |
157 rect_x = rect_x + ginfo['size'] | |
158 context.rectangle(rect_x, rect_y, ginfo['size'], | |
159 ginfo['size']) | |
160 else: | |
161 raise | |
162 | |
163 context.set_source_rgba(*self.rgba_state[gpio_state]) | |
164 context.fill() | |
165 | |
166 if ginfo['arrow'] is not None: | |
167 arrow_x = ginfo['arrow']['x'] | |
168 arrow_y = ginfo['arrow']['y'] | |
169 arrow_l = ginfo['arrow']['length'] | |
170 arrow_w = ginfo['arrow']['width'] | |
171 | |
172 arrow_dir = ginfo['arrow']['direction'] | |
173 if (gpio_state == 1) and (ginfo['type'] == 'switch'): | |
174 arrow_dir =+ 180 | |
175 | |
176 self.show_arrow(context, ginfo['cx'], ginfo['cy'], | |
177 arrow_x, arrow_y, arrow_w, arrow_l, arrow_dir) | |
178 | |
179 context.scale(widget_width / 1.0, widget_height / 1.0) | |
180 context.set_source_rgba(0.1, 0.1, 0.1, 0.95) | |
181 context.select_font_face( | |
182 'Verdana', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) | |
183 context.set_font_size(.05) | |
184 | |
185 if gpio_state > 0: | |
186 dtext = "%s %s %s now [ %d ] " % \ | |
187 (text[gpio_state], name, ginfo['type'], | |
188 (self._deadline - int(time.time()))) | |
189 else: | |
190 dtext = "%s with %s %s" % (text[gpio_state], name, ginfo['type']) | |
191 | |
192 x_bearing, y_bearing, width, height = context.text_extents(dtext)[:4] | |
193 context.move_to(0.5 - (width / 2) - x_bearing, | |
194 0.5 - (height / 2) - y_bearing) | |
195 context.show_text(dtext) | |
196 context.restore() | |
197 return True | |
198 | |
199 def expose_event(self, widget, event): | |
200 context = widget.window.cairo_create() | |
201 | |
202 context.set_source_surface(self._devrec_image, 0, 0) | |
203 context.paint() | |
204 | |
205 if self._success is None: | |
206 for key in self.gpio_info: | |
207 if key not in self._successful: | |
208 self.request_action(widget, context, key) | |
209 break | |
210 return True | |
211 | |
212 def timer_event(self, window): | |
213 if not self._deadline: | |
214 # Ignore timer events with no countdown in progress. | |
215 return True | |
216 if self._deadline <= time.time(): | |
217 self._deadline = None | |
218 if self._success is None: | |
219 self._success = False | |
220 elif self._success: | |
221 sys.exit(0) | |
222 window.queue_draw() | |
223 return True | |
224 | |
225 class devrec_gpio: | |
226 ''' | |
227 Borrowed from site_tests/hardware_GPIOSwitches. Will replace | |
228 iotools implementation with successor chromium-os issue id=3119 | |
229 ''' | |
230 | |
231 def __init__(self, autodir): | |
232 self._autodir = autodir | |
233 self.gpio_read = None | |
234 self.table = None | |
235 | |
236 def cfg(self): | |
237 self.sku_table = { | |
238 # SKU: gpio_read, recovery GPIO, developer mode, | |
239 # firmware writeprotect | |
240 'atom-proto': {'gpio_read': self.pinetrail_gpio_read, | |
241 # name : [<bit>, <type>, <default>, | |
242 # <assert>, <state>] | |
243 # <type> == button || switch || ro (read-only) | |
244 # <default> == 0 || 1 | |
245 # <state> == number counts down 0 | |
246 'developer': [7, 1, 2], | |
247 | |
248 'recovery': [6, 1, 2], | |
249 }, | |
250 } | |
251 | |
252 # TODO(nsanders): Detect actual system type here by HWQual ID (?) | |
253 # and redirect to the correct check. | |
254 # We're just checking for any Atom here, and hoping for the best. | |
255 if not os.system('cat /proc/cpuinfo | grep "model name" | ' | |
256 'grep -qe "N4[0-9][0-9]"'): | |
257 systemsku = 'atom-proto' | |
258 else: | |
259 systemsku = 'unknown' | |
260 | |
261 # Look up hardware configuration. | |
262 if systemsku in self.sku_table: | |
263 table = self.sku_table[systemsku] | |
264 self.table = table | |
265 self.gpio_read = table['gpio_read'] | |
266 else: | |
267 raise KeyError('System settings not defined for board %s' % | |
268 systemsku) | |
269 | |
270 def pinetrail_gpio_read(self, name): | |
271 if not self.table.__contains__(name): | |
272 raise | |
273 | |
274 # Tigerpoint LPC Interface. | |
275 tp_device = (0, 31, 0) | |
276 # TP io port location of GPIO registers. | |
277 tp_GPIOBASE = 0x48 | |
278 # IO offset to check GPIO levels. | |
279 tp_GP_LVL_off = 0xc | |
280 | |
281 try: | |
282 tp_gpio_iobase_str = os.popen('pci_read32 %s %s %s %s' % ( | |
283 tp_device[0], tp_device[1], tp_device[2], | |
284 tp_GPIOBASE)).readlines()[0] | |
285 except: | |
286 print "ERROR: reading gpio iobase" | |
287 | |
288 | |
289 # Bottom bit of GPIOBASE is a flag indicating io space. | |
290 tp_gpio_iobase = long(tp_gpio_iobase_str, 16) & ~1 | |
291 | |
292 try: | |
293 tp_gpio_mask_str = os.popen('io_read32 %s' % ( | |
294 tp_gpio_iobase + tp_GP_LVL_off)).readlines()[0] | |
295 except: | |
296 print "ERROR: reading gpio value" | |
297 | |
298 tp_gpio_mask = long(tp_gpio_mask_str, 16) | |
299 | |
300 gpio_val = int((tp_gpio_mask >> self.table[name][0]) & 1) | |
301 return gpio_val | |
302 | |
303 def make_test_widget(autodir, devrec_image): | |
304 test = DevRecTest(autodir, devrec_image) | |
305 | |
306 image_size = (devrec_image.get_width(), devrec_image.get_height()) | |
307 | |
308 drawing_area = gtk.DrawingArea() | |
309 drawing_area.set_size_request(*image_size) | |
310 drawing_area.connect('expose_event', test.expose_event) | |
311 drawing_area.add_events(gtk.gdk.EXPOSURE_MASK) | |
312 gobject.timeout_add(200, test.timer_event, drawing_area) | |
313 | |
314 test.start_countdown(test.timeout) | |
315 | |
316 return drawing_area | |
OLD | NEW |