| # -*- coding: utf-8 -*- |
| # |
| # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| |
| # DESCRIPTION : |
| # |
| # This is a factory test to test the LEDs (wifi, battery, etc). |
| |
| |
| import cairo |
| import gtk |
| import pango |
| import os |
| import subprocess |
| import sys |
| import re |
| |
| from cmath import pi |
| from gtk import gdk |
| |
| from autotest_lib.client.bin import test |
| from autotest_lib.client.bin import utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.cros import factory |
| from autotest_lib.client.cros.factory import ui as ful |
| |
| |
| _LABEL_STATUS_SIZE = (140, 30) |
| _LABEL_FONT = pango.FontDescription('courier new condensed 16') |
| _LABEL_FG = gtk.gdk.color_parse('light green') |
| _LABEL_UNTESTED_FG = gtk.gdk.color_parse('grey40') |
| |
| _PATTERN_LABEL_STR = 'pattern / 圖樣: ' |
| |
| _ORANGE = gtk.gdk.color_parse('orange') |
| |
| _LED_NAMES = 'sleepled battchgled wlan battfulled powerled 3g'.split() |
| _ORANGE_LED_NAMES = _LED_NAMES[0:3] |
| _BLUE_LED_NAMES = _LED_NAMES[3:] |
| |
| _LED_COUNT = 3 |
| _LED_Y_OFFSET = 10 |
| _LED_X_OFFSETS = [10, 80, 150] |
| _LED_RADIUS = 18 |
| _SHFL_XYR = {'x':166,'y':20, 'r':9} |
| |
| |
| def run_led_ctl(led_ctl_path, args): |
| rc = subprocess.call([led_ctl_path] + args.split()) |
| if rc != 1: |
| factory.log('%s(%s) failed with rc %s' % (led_ctl_path, args, rc)) |
| |
| |
| def pattern_all_off(led_ctl_fn): |
| for n in _LED_NAMES: |
| led_ctl_fn('-%s -off' % n) |
| return [ful.BLACK, ful.BLACK, ful.BLACK] |
| |
| def pattern_blue_on(led_ctl_fn): |
| pattern_all_off(led_ctl_fn) |
| for n in _BLUE_LED_NAMES: |
| led_ctl_fn('-%s -on' % n) |
| return [ful.BLUE, ful.BLUE, ful.BLUE] |
| |
| def pattern_orange_on(led_ctl_fn): |
| pattern_all_off(led_ctl_fn) |
| for n in _ORANGE_LED_NAMES: |
| led_ctl_fn('-%s -on' % n) |
| return [_ORANGE, _ORANGE, _ORANGE] |
| |
| _PATTERN_LIST = [ |
| ('all off', pattern_all_off), |
| ('blue on', pattern_blue_on), |
| ('orange on', pattern_orange_on), |
| ('shift led', False)] |
| |
| |
| class factory_Leds(test.test): |
| version = 1 |
| preserve_srcdir = True |
| |
| def goto_next_pattern(self): |
| if not self._pattern_queue: |
| gtk.main_quit() |
| return |
| self._current_pattern, cb_fn = self._pattern_queue.pop() |
| self._status_map[self._current_pattern] = ful.ACTIVE |
| if cb_fn: |
| led_ctl_fn = lambda args: run_led_ctl(self._led_ctl_path, args) |
| self._led_colors = cb_fn(led_ctl_fn) |
| else: |
| self._pattern_da.connect('expose_event', self.shift_led_expose) |
| self._pattern_da.queue_draw() |
| |
| def shift_led_expose(self, widget, event): |
| context = widget.window.cairo_create() |
| context.set_source_surface(self._shf_image, 0, 0) |
| context.paint() |
| |
| if self._shift_cnt is 2: |
| if self._shift_color is ful.BLACK: |
| self._shift_color = ful.BLUE |
| else: |
| self._shift_color = ful.BLACK |
| self._shift_cnt = 0 |
| context.set_source_color(self._shift_color) |
| context.arc(_SHFL_XYR['x'], _SHFL_XYR['y'], _SHFL_XYR['r'], |
| 0.0, 2.0 * pi) |
| context.fill() |
| |
| def pattern_expose(self, widget, event): |
| context = widget.window.cairo_create() |
| context.set_source_surface(self._leds_image, 0, 0) |
| context.paint() |
| for led_index in range(_LED_COUNT): |
| color = self._led_colors[led_index] |
| x_offset = _LED_X_OFFSETS[led_index] + _LED_RADIUS + 3 |
| y_offset = _LED_Y_OFFSET + _LED_RADIUS + 3 |
| context.set_source_color(color) |
| context.arc(x_offset, y_offset, _LED_RADIUS, 0.0, 2.0 * pi) |
| context.fill() |
| |
| def quit(self): |
| factory.log('releasing LEDs ...') |
| run_led_ctl(self._led_ctl_path, '-ledrelease') |
| |
| def label_status_expose(self, widget, event, name=None): |
| status = self._status_map[name] |
| widget.set_text(status) |
| widget.modify_fg(gtk.STATE_NORMAL, ful.LABEL_COLORS[status]) |
| |
| def make_pattern_label_box(self, name): |
| eb = gtk.EventBox() |
| eb.modify_bg(gtk.STATE_NORMAL, ful.BLACK) |
| label_status = gtk.Label(ful.UNTESTED) |
| label_status.set_size_request(*_LABEL_STATUS_SIZE) |
| label_status.set_alignment(0, 0.5) |
| label_status.modify_font(_LABEL_FONT) |
| label_status.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) |
| expose_cb = lambda *x: self.label_status_expose(*x, **{'name':name}) |
| label_status.connect('expose_event', expose_cb) |
| label_en = gtk.Label(name) |
| label_en.set_alignment(1, 0.5) |
| label_en.modify_font(_LABEL_FONT) |
| label_en.modify_fg(gtk.STATE_NORMAL, _LABEL_FG) |
| label_sep = gtk.Label(' : ') |
| label_sep.set_alignment(0.5, 0.5) |
| label_sep.modify_font(_LABEL_FONT) |
| label_sep.modify_fg(gtk.STATE_NORMAL, _LABEL_FG) |
| hbox = gtk.HBox() |
| hbox.pack_end(label_status, False, False) |
| hbox.pack_end(label_sep, False, False) |
| hbox.pack_end(label_en, False, False) |
| eb.add(hbox) |
| return eb |
| |
| def key_release_callback(self, widget, event): |
| if event.keyval == gtk.keysyms.Tab: |
| self._status_map[self._current_pattern] = ful.FAILED |
| self.goto_next_pattern() |
| elif event.keyval == gtk.keysyms.Return: |
| self._status_map[self._current_pattern] = ful.PASSED |
| self.goto_next_pattern() |
| elif self._current_pattern.startswith("shift") and \ |
| event.keyval == gtk.keysyms.Shift_L: |
| self._shift_cnt += 1 |
| self._pattern_da.queue_draw() |
| return True |
| |
| def register_callbacks(self, window): |
| window.connect('key-release-event', self.key_release_callback) |
| window.add_events(gdk.KEY_RELEASE_MASK) |
| |
| def _get_embedded_controller_vendor(self): |
| # example output of superiotool: |
| # Found Nuvoton WPCE775x (id=0x05, rev=0x02) at 0x2e |
| re_vendor = re.compile(r'Found (\w*)') |
| vendor = [] |
| res = utils.system_output('superiotool', ignore_status=True).split('\n') |
| for line in res: |
| match = re_vendor.search(line) |
| if match: |
| vendor.append(match.group(1)) |
| return vendor |
| |
| def run_once(self, led_ctl_path=None): |
| |
| factory.log('%s run_once' % self.__class__) |
| |
| ec_vendor = self._get_embedded_controller_vendor() |
| if len(ec_vendor) == 0: |
| raise error.TestNAError('No embedded controller vendor found') |
| if 'Nuvoton' not in ec_vendor: |
| raise error.TestNAError('Currently not supported embedded controllers: %s' % |
| ', '.join(ec_vendor)) |
| |
| self._led_ctl_path = led_ctl_path |
| if not os.path.exists(self._led_ctl_path): |
| raise error.TestNAError('Command %s does not exist' % |
| self._led_ctl_path) |
| |
| self._shift_color = ful.BLACK |
| self._shift_cnt = 0 |
| |
| os.chdir(self.srcdir) |
| try: |
| image = cairo.ImageSurface.create_from_png('leds.png') |
| except cairo.Error as e: |
| raise error.TestNAError('Error while opening leds.png: %s' % |
| e.message) |
| image_size = (image.get_width(), image.get_height()) |
| self._leds_image = image |
| |
| image = cairo.ImageSurface.create_from_png('shf.png') |
| self._shf_image = image |
| |
| self._pattern_queue = [x for x in reversed(_PATTERN_LIST)] |
| self._status_map = dict((n, ful.UNTESTED) for n, f in _PATTERN_LIST) |
| |
| pattern_da = gtk.DrawingArea() |
| pattern_da.set_size_request(*image_size) |
| pattern_da.connect('expose_event', self.pattern_expose) |
| self._pattern_da = pattern_da |
| |
| pattern_label = ful.make_label(_PATTERN_LABEL_STR) |
| |
| pattern_box = gtk.HBox() |
| pattern_box.pack_start(pattern_label, False, False) |
| pattern_box.pack_start(pattern_da, False, False) |
| |
| prompt_label = ful.make_label(ful.USER_PASS_FAIL_SELECT_STR) |
| |
| subvbox = gtk.VBox() |
| for name, cb_fun in _PATTERN_LIST: |
| label_box = self.make_pattern_label_box(name) |
| subvbox.pack_start(label_box, False, False) |
| |
| vbox = gtk.VBox() |
| vbox.set_spacing(20) |
| vbox.pack_start(prompt_label, False, False) |
| vbox.pack_start(pattern_box, False, False) |
| vbox.pack_start(subvbox, False, False) |
| |
| test_widget = gtk.EventBox() |
| test_widget.modify_bg(gtk.STATE_NORMAL, ful.BLACK) |
| test_widget.add(vbox) |
| self._test_widget = test_widget |
| |
| self.goto_next_pattern() |
| |
| ful.run_test_widget(self.job, test_widget, |
| window_registration_callback=self.register_callbacks, |
| cleanup_callback=self.quit) |
| |
| failed_set = set(name for name, status in self._status_map.items() |
| if status is not ful.PASSED) |
| if failed_set: |
| raise error.TestFail('Some patterns failed\n' \ |
| '以下圖樣測試未通過: %s' % |
| ', '.join(failed_set)) |
| |
| factory.log('%s run_once finished' % self.__class__) |