| 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 |