Index: client/site_tests/factory_DeveloperRecovery/factory_DeveloperRecovery.py |
diff --git a/client/site_tests/factory_DeveloperRecovery/factory_DeveloperRecovery.py b/client/site_tests/factory_DeveloperRecovery/factory_DeveloperRecovery.py |
index 266ddf3044a4b72a67722f60cac18a9cb81a9da2..2173e29060aff0c18b006a2fafda442dea6dde94 100644 |
--- a/client/site_tests/factory_DeveloperRecovery/factory_DeveloperRecovery.py |
+++ b/client/site_tests/factory_DeveloperRecovery/factory_DeveloperRecovery.py |
@@ -12,53 +12,340 @@ |
# switch and restore the Developer switch and press/release the |
# Recovery button. Success at each step resets a 20 second countdown timer. |
-from autotest_lib.client.bin import test |
-from autotest_lib.client.common_lib import error |
-from autotest_lib.client.common_lib import factory_test |
-import gtk |
import cairo |
+import gobject |
+import gtk |
+import sys |
+import time |
import os |
+import math |
+ |
+from autotest_lib.client.bin import factory |
+from autotest_lib.client.bin import factory_ui_lib as ful |
+from autotest_lib.client.bin import test |
+from autotest_lib.client.common_lib import error |
+ |
+ |
+class DevRecTest(): |
+ |
+ gpio_info = { |
+ 'developer' : {'type' : 'switch', |
+ 'cx' : 355, |
+ 'cy' : 175, |
+ 'size' : 30, |
+ 'arrow' : {'x' : 305, |
+ 'y' : 175, |
+ 'width' : 15, |
+ 'length' : 100, |
+ # in degrees starts as rt arrow |
+ 'direction' : 0, |
+ }, |
+ }, |
+ 'recovery' : {'type' : 'button', |
+ 'cx' : 635, |
+ 'cy' : 425, |
+ 'size' : 30, |
+ 'arrow' : {'x' : 580, |
+ 'y' : 425, |
+ 'width' : 15, |
+ 'length' : 100, |
+ 'direction' : 270, |
+ } |
+ }, |
+ } |
+ |
+ # How long DevRecTest allows in seconds until failing |
+ timeout = 20 |
+ |
+ # How long to display the success message in seconds before exit. |
+ pass_msg_timeout = 2 |
+ |
+ # Background color and alpha for the final result message. |
+ bg_rgba_fail = (0.7, 0, 0, 0.9) |
+ bg_rgba_pass = ( 0, 0.7, 0, 0.9) |
+ |
+ rgba_state = [(0.0, 1.0, 0.0, 0.9), |
+ (0.9, 0.9, 0.0, 0.6), |
+ (0.9, 0.0, 0.0, 0.6)] |
+ |
+ def __init__(self, autodir, devrec_image): |
+ self._devrec_image = devrec_image |
+ self._successful = set() |
+ self._deadline = None |
+ self._success = None |
+ self.gpios = DevRecGpio(autodir) |
+ self.gpios.cfg() |
+ |
+ def show_arrow(self, context, cx, cy, headx, heady, awidth, length, |
+ degrees): |
+ |
+ '''Draw a simple arrow in given context. |
+ ''' |
+ |
+ context.save() |
+ |
+ # rotation transform |
+ matrix = cairo.Matrix(1, 0, 0, 1, 0, 0) |
+ context.set_source_rgba(0, 0, 0, 1) |
+ cairo.Matrix.translate(matrix, cx, cy) |
+ cairo.Matrix.rotate(matrix, math.radians(degrees)) |
+ cairo.Matrix.translate(matrix, -cx, -cy) |
+ context.transform(matrix) |
+ |
+ # right arrow default |
+ context.set_line_width(5) |
+ context.move_to(headx, heady) |
+ context.rel_line_to(-awidth, -awidth/2.0) |
+ context.rel_line_to(0, awidth) |
+ context.rel_line_to(awidth, -awidth/2.0) |
+ context.fill_preserve() |
+ context.rel_line_to(-length, 0) |
+ context.stroke_preserve() |
+ context.set_source_rgba(0, 0, 0, 0.5) |
+ context.stroke_preserve() |
+ context.restore() |
+ |
+ def start_countdown(self, duration): |
+ self._deadline = int(time.time()) + duration |
+ |
+ def request_action(self, widget, context, name): |
+ '''Determine action required by gpio state and show |
+ ''' |
+ |
+ gpio_default = self.gpios.table[name][1] |
+ gpio_state = self.gpios.table[name][2] |
+ gpio_val = self.gpios.gpio_read(name) |
+ |
+ # state transitions based on current value |
+ if (gpio_state == 2) and (gpio_val != gpio_default): |
+ gpio_state-=1 |
+ # refresh countdown |
+ self.start_countdown(self.timeout) |
+ elif (gpio_state == 1) and (gpio_val == gpio_default): |
+ gpio_state-=1 |
+ self._successful.add(name) |
+ if self.gpio_info.__len__() is self._successful.__len__(): |
+ self._success = True |
+ self.start_countdown(self.pass_msg_timeout) |
+ |
+ # store state change |
+ self.gpios.table[name][2] = gpio_state |
+ |
+ widget_width, widget_height = widget.get_size_request() |
+ context.save() |
+ ginfo = self.gpio_info[name] |
+ |
+ context.set_source_rgba(0, 0, 0, 1) |
+ |
+ if (ginfo['type'] == 'button'): |
+ text = ['Done', 'Release', 'Press'] |
+ context.arc(ginfo['cx'], ginfo['cy'], ginfo['size'], |
+ 0, math.radians(360)) |
+ context.stroke() |
+ context.arc(ginfo['cx'], ginfo['cy'], ginfo['size'], |
+ 0, math.radians(360)) |
+ elif (ginfo['type'] == 'switch'): |
+ text = ['Done', 'Restore', 'Move'] |
+ # two rects one outline of switch body the other |
+ # representing the position |
+ rect_x = ginfo['cx'] - ginfo['size'] |
+ rect_y = ginfo['cy'] - ginfo['size'] / 2.0 |
+ context.rectangle(rect_x, rect_y, ginfo['size'] * 2, |
+ ginfo['size']) |
+ |
+ context.stroke() |
+ |
+ if gpio_state == 1: |
+ rect_x = rect_x + ginfo['size'] |
+ context.rectangle(rect_x, rect_y, ginfo['size'], |
+ ginfo['size']) |
+ else: |
+ raise |
+ |
+ context.set_source_rgba(*self.rgba_state[gpio_state]) |
+ context.fill() |
+ |
+ if ginfo['arrow'] is not None: |
+ arrow_x = ginfo['arrow']['x'] |
+ arrow_y = ginfo['arrow']['y'] |
+ arrow_l = ginfo['arrow']['length'] |
+ arrow_w = ginfo['arrow']['width'] |
+ |
+ arrow_dir = ginfo['arrow']['direction'] |
+ if (gpio_state == 1) and (ginfo['type'] == 'switch'): |
+ arrow_dir =+ 180 |
+ |
+ self.show_arrow(context, ginfo['cx'], ginfo['cy'], |
+ arrow_x, arrow_y, arrow_w, arrow_l, arrow_dir) |
+ |
+ context.scale(widget_width / 1.0, widget_height / 1.0) |
+ context.set_source_rgba(0.1, 0.1, 0.1, 0.95) |
+ context.select_font_face( |
+ 'Verdana', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) |
+ context.set_font_size(.05) |
+ |
+ if gpio_state > 0: |
+ dtext = "%s %s %s now [ %d ] " % \ |
+ (text[gpio_state], name, ginfo['type'], |
+ (self._deadline - int(time.time()))) |
+ else: |
+ dtext = "%s with %s %s" % (text[gpio_state], name, ginfo['type']) |
+ |
+ x_bearing, y_bearing, width, height = context.text_extents(dtext)[:4] |
+ context.move_to(0.5 - (width / 2) - x_bearing, |
+ 0.5 - (height / 2) - y_bearing) |
+ context.show_text(dtext) |
+ context.restore() |
+ return True |
+ |
+ def expose_event(self, widget, event): |
+ context = widget.window.cairo_create() |
+ |
+ context.set_source_surface(self._devrec_image, 0, 0) |
+ context.paint() |
+ |
+ if self._success is None: |
+ for key in self.gpio_info: |
+ if key not in self._successful: |
+ self.request_action(widget, context, key) |
+ break |
+ return True |
+ |
+ def timer_event(self, window): |
+ if not self._deadline: |
+ # Ignore timer events with no countdown in progress. |
+ return True |
+ if self._deadline <= time.time(): |
+ self._deadline = None |
+ if self._success is None: |
+ self._success = False |
+ elif self._success: |
+ sys.exit(0) |
+ window.queue_draw() |
+ return True |
+ |
+ |
+class DevRecGpio: |
+ ''' |
+ Borrowed from site_tests/hardware_GPIOSwitches. Will replace |
+ iotools implementation with successor chromium-os issue id=3119 |
+ ''' |
+ |
+ def __init__(self, autodir): |
+ self._autodir = autodir |
+ self.gpio_read = None |
+ self.table = None |
+ |
+ def cfg(self): |
+ self.sku_table = { |
+ # SKU: gpio_read, recovery GPIO, developer mode, |
+ # firmware writeprotect |
+ 'atom-proto': {'gpio_read': self.pinetrail_gpio_read, |
+ # name : [<bit>, <type>, <default>, |
+ # <assert>, <state>] |
+ # <type> == button || switch || ro (read-only) |
+ # <default> == 0 || 1 |
+ # <state> == number counts down 0 |
+ 'developer': [7, 1, 2], |
+ |
+ 'recovery': [6, 1, 2], |
+ }, |
+ } |
+ |
+ # TODO(nsanders): Detect actual system type here by HWQual ID (?) |
+ # and redirect to the correct check. |
+ # We're just checking for any Atom here, and hoping for the best. |
+ if not os.system('cat /proc/cpuinfo | grep "model name" | ' |
+ 'grep -qe "N4[0-9][0-9]"'): |
+ systemsku = 'atom-proto' |
+ else: |
+ systemsku = 'unknown' |
+ |
+ # Look up hardware configuration. |
+ if systemsku in self.sku_table: |
+ table = self.sku_table[systemsku] |
+ self.table = table |
+ self.gpio_read = table['gpio_read'] |
+ else: |
+ raise KeyError('System settings not defined for board %s' % |
+ systemsku) |
+ |
+ def pinetrail_gpio_read(self, name): |
+ if not self.table.__contains__(name): |
+ raise |
+ |
+ # Tigerpoint LPC Interface. |
+ tp_device = (0, 31, 0) |
+ # TP io port location of GPIO registers. |
+ tp_GPIOBASE = 0x48 |
+ # IO offset to check GPIO levels. |
+ tp_GP_LVL_off = 0xc |
+ |
+ try: |
+ tp_gpio_iobase_str = os.popen('pci_read32 %s %s %s %s' % ( |
+ tp_device[0], tp_device[1], tp_device[2], |
+ tp_GPIOBASE)).readlines()[0] |
+ except: |
+ factory.log("ERROR: reading gpio iobase") |
+ |
+ |
+ # Bottom bit of GPIOBASE is a flag indicating io space. |
+ tp_gpio_iobase = long(tp_gpio_iobase_str, 16) & ~1 |
+ |
+ try: |
+ tp_gpio_mask_str = os.popen('io_read32 %s' % ( |
+ tp_gpio_iobase + tp_GP_LVL_off)).readlines()[0] |
+ except: |
+ factory.log("ERROR: reading gpio value") |
+ |
+ tp_gpio_mask = long(tp_gpio_mask_str, 16) |
+ |
+ gpio_val = int((tp_gpio_mask >> self.table[name][0]) & 1) |
+ return gpio_val |
-import DevRecTest |
class factory_DeveloperRecovery(test.test): |
version = 1 |
preserve_srcdir = True |
def key_release_callback(self, widget, event): |
- char = event.keyval in range(32,127) and chr(event.keyval) or None |
- factory_test.XXX_log('key_release_callback %s(%s)' % |
- (event.keyval, char)) |
- if event.keyval == self.quit_key: |
- factory_test.XXX_log('%s exiting...' % self.tagged_testname) |
- gtk.main_quit() |
- factory_test.test_switch_on_trigger(event) |
+ self._ft_state.exit_on_trigger(event) |
return True |
def register_callbacks(self, window): |
window.connect('key-release-event', self.key_release_callback) |
window.add_events(gtk.gdk.KEY_RELEASE_MASK) |
- def run_once(self, test_widget_size=None, trigger_set=None, layout='devrec', |
- result_file_path=None, quit_key=ord('Q'), |
- msg='factory_DeveloperRecovery'): |
+ def run_once(self, |
+ test_widget_size=None, |
+ trigger_set=None, |
+ result_file_path=None, |
+ layout=None): |
- factory_test.XXX_log(self.tagged_testname) |
+ factory.log('%s run_once' % self.__class__) |
- self.quit_key = quit_key |
- |
- factory_test.init(trigger_set=trigger_set, |
- result_file_path=result_file_path) |
+ self._ft_state = ful.State( |
+ trigger_set=trigger_set, |
+ result_file_path=result_file_path) |
os.chdir(self.srcdir) |
dr_image = cairo.ImageSurface.create_from_png('%s.png' % layout) |
+ image_size = (dr_image.get_width(), dr_image.get_height()) |
+ |
+ test = DevRecTest(autodir, dr_image) |
+ |
+ drawing_area = gtk.DrawingArea() |
+ drawing_area.set_size_request(*image_size) |
+ drawing_area.connect('expose_event', test.expose_event) |
+ drawing_area.add_events(gtk.gdk.EXPOSURE_MASK) |
+ gobject.timeout_add(200, test.timer_event, drawing_area) |
- test_widget = DevRecTest.make_test_widget(self.autodir, dr_image) |
+ test.start_countdown(test.timeout) |
- factory_test.run_test_widget( |
- test_widget=test_widget, |
+ self._ft_state.run_test_widget( |
+ test_widget=drawing_area, |
test_widget_size=test_widget_size, |
window_registration_callback=self.register_callbacks) |
- factory_test.XXX_log('exiting %s' % self.tagged_testname) |
+ factory.log('%s run_once finished' % self.__class__) |