| # -*- coding: utf-8 -*- |
| # |
| # Copyright (c) 2013 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. |
| |
| """A factory test for checking touchscreen uniformity. |
| |
| This test is intended to be run during run-in without a fixture or operator. |
| The test recalibrates the touchscreen then reads raw reference (baseline) data. |
| Each value must fall within a specified max and min range. Delta values (the |
| baseline - current reading) are also checked. |
| |
| Sample test_list entry:: |
| |
| OperatorTest( |
| id='TouchscreenUniformity', |
| label_zh=u'触屏均一性测试', |
| run_if='device_data.component.has_touchscreen', |
| pytest_name='touchscreen_uniformity', |
| dargs={'deltas_max_val': 40, |
| 'deltas_min_val': -30, |
| 'refs_max_val': 25100, |
| 'refs_min_val': 23400}) |
| |
| The args thresholds in need to be experimentally determined by checking |
| a set of machines. The test logs the actual max and min values found. |
| """ |
| |
| import logging |
| import time |
| import unittest |
| |
| import factory_common # pylint: disable=unused-import |
| from cros.factory.device import device_utils |
| from cros.factory.external import numpy |
| from cros.factory.test import event_log |
| from cros.factory.test import factory_task |
| from cros.factory.test import test_ui |
| from cros.factory.test import ui_templates |
| from cros.factory.utils.arg_utils import Arg |
| |
| |
| _LABEL_CALIBRATING_TOUCHSCREEN = test_ui.MakeLabel('Calibrating Touchscreen', |
| u'触屏校正中', 'test-info') |
| _LABEL_NOT_FOUND = test_ui.MakeLabel('ERROR: Touchscreen Not Found', |
| u'没有找到触屏', 'test-fail') |
| _LABEL_TESTING_REFERENCES = test_ui.MakeLabel('Testing References', |
| u'参考值测试中', 'test-info') |
| _LABEL_TESTING_DELTAS = test_ui.MakeLabel('Testing Deltas', |
| u'差量测试中', 'test-info') |
| _LABEL_PASS = test_ui.MakeLabel('PASS', u'成功', 'test-pass') |
| _LABEL_FAIL = test_ui.MakeLabel('FAIL', u'失败', 'test-fail') |
| _MESSAGE_DELAY_SECS = 1 |
| |
| _BR = '<br/>' |
| |
| _CSS = """ |
| .test-info {font-size: 2em;} |
| .test-pass {font-size: 2em; color:green;} |
| .test-fail {font-size: 2em; color:red;} |
| """ |
| |
| |
| class CalibrateTouchscreenTask(factory_task.FactoryTask): |
| """Recalibrates the touch controller.""" |
| |
| def __init__(self, test): |
| super(CalibrateTouchscreenTask, self).__init__() |
| self.template = test.template |
| self.touchscreen = test.touchscreen |
| |
| def Run(self): |
| self.template.SetState(_LABEL_CALIBRATING_TOUCHSCREEN) |
| if self.touchscreen.CalibrateController(): |
| self.template.SetState(' ' + _LABEL_PASS + _BR, append=True) |
| self.Pass() |
| else: |
| self.template.SetState(' ' + _LABEL_FAIL + _BR, append=True) |
| self.Fail('Touchscreen calibration failed.') |
| |
| |
| class CheckRawDataTask(factory_task.FactoryTask): |
| """Checks raw controler data is in an expected range. |
| |
| Args: |
| test: The factory test calling this task. |
| data_name: String. A short name of the data type being checked. The name |
| must match the sysfs entries under the I2C device path. |
| ui_label: String. Formatted HTML to append to the test UI. |
| FetchData: The function to call to retrieve the test data to check. |
| min_val: Int. The lower bound to check the raw data against. |
| max_val: Int. The upper bound to check the raw data against. |
| """ |
| |
| def __init__(self, test, data_name, ui_label, FetchData, min_val, max_val): |
| super(CheckRawDataTask, self).__init__() |
| self.template = test.template |
| self.data_name = data_name |
| self.ui_label = ui_label |
| self.FetchData = FetchData |
| self.min_val = min_val |
| self.max_val = max_val |
| |
| def checkRawData(self): |
| """Checks that data from self.FetchData is within bounds. |
| |
| Returns: |
| True if the data is in bounds. |
| """ |
| logging.info('Checking %s values are between %d and %d', |
| self.data_name, self.min_val, self.max_val) |
| check_passed = True |
| data = self.FetchData() |
| for row_index in xrange(len(data)): |
| for col_index in xrange(len(data[row_index])): |
| val = data[row_index][col_index] |
| if not self.min_val <= val <= self.max_val: |
| logging.info( |
| 'Raw data out of range: row=%d, col=%s, val=%d', |
| row_index, col_index, val) |
| check_passed = False |
| |
| merged_data = sum(data, []) |
| actual_min_val = min(merged_data) |
| actual_max_val = max(merged_data) |
| standard_deviation = float(numpy.std(merged_data)) |
| logging.info('Lowest value: %d', actual_min_val) |
| logging.info('Highest value: %d', actual_max_val) |
| logging.info('Standard deviation %f', standard_deviation) |
| event_log.Log('touchscreen_%s_stats' % self.data_name, |
| allowed_min_val=self.min_val, |
| allowed_max_val=self.max_val, |
| acutal_min_val=actual_min_val, |
| acutal_max_val=actual_max_val, |
| standard_deviation=standard_deviation, |
| test_passed=check_passed) |
| |
| return check_passed |
| |
| def Run(self): |
| self.template.SetState(self.ui_label, append=True) |
| if self.checkRawData(): |
| self.template.SetState(' ' + _LABEL_PASS + _BR, append=True) |
| self.Pass() |
| else: |
| self.template.SetState(' ' + _LABEL_FAIL + _BR, append=True) |
| self.Fail('Uniformity check on %s failed.' % self.data_name, later=True) |
| |
| |
| class CheckReferencesTask(CheckRawDataTask): |
| """Checks refernece data is in an expected range.""" |
| |
| def __init__(self, test): |
| super(CheckReferencesTask, self).__init__( |
| test, 'refs', _LABEL_TESTING_REFERENCES, |
| test.touchscreen.GetRefValues, test.args.refs_min_val, |
| test.args.refs_max_val) |
| |
| |
| class CheckDeltasTask(CheckRawDataTask): |
| """Checks delta data is in an expected range.""" |
| |
| def __init__(self, test): |
| super(CheckDeltasTask, self).__init__( |
| test, 'deltas', _LABEL_TESTING_DELTAS, |
| test.touchscreen.GetDeltaValues, test.args.deltas_min_val, |
| test.args.deltas_max_val) |
| |
| |
| class CheckTouchController(factory_task.FactoryTask): |
| """Verifies that the touch controler interface exists.""" |
| |
| def __init__(self, test): |
| super(CheckTouchController, self).__init__() |
| self.template = test.template |
| self.touchscreen = test.touchscreen |
| |
| def Run(self): |
| if self.touchscreen.CheckController(): |
| self.Pass() |
| else: |
| self.template.SetState(_LABEL_NOT_FOUND) |
| time.sleep(_MESSAGE_DELAY_SECS) |
| self.Fail('Touch controller not found.') |
| |
| |
| class WaitTask(factory_task.FactoryTask): |
| """Waits for a specified number of seconds. |
| |
| Args: |
| delay: Number of seconds to wait. |
| """ |
| |
| def __init__(self, delay): |
| super(WaitTask, self).__init__() |
| self.delay = delay |
| |
| def Run(self): |
| time.sleep(self.delay) |
| self.Pass() |
| |
| |
| class TouchscreenUniformity(unittest.TestCase): |
| ARGS = [ |
| Arg('refs_max_val', int, 'Maximum value for reference data.'), |
| Arg('refs_min_val', int, 'Minimum value for reference data.'), |
| Arg('deltas_max_val', int, 'Maximum value for delta data.'), |
| Arg('deltas_min_val', int, 'Minimum value for delta data.'), |
| Arg('matrix_size', tuple, |
| 'The size of touchscreen sensor row data for enabled sensors in the ' |
| 'form of (rows, cols). This is used when the matrix size read from ' |
| 'kernel i2c device path is different from the matrix size of ' |
| 'enabled sensors.', |
| optional=True)] |
| |
| def setUp(self): |
| self.ui = test_ui.UI() |
| self.template = ui_templates.OneSection(self.ui) |
| self.ui.AppendCSS(_CSS) |
| self.touchscreen = device_utils.CreateDUTInterface().touchscreen |
| self.touchscreen.SetSubmatrixSize(self.args.matrix_size) |
| |
| def runTest(self): |
| task_list = [ |
| CheckTouchController(self), |
| CalibrateTouchscreenTask(self), |
| CheckReferencesTask(self), |
| CheckDeltasTask(self), |
| WaitTask(_MESSAGE_DELAY_SECS) |
| ] |
| task_manager = factory_task.FactoryTaskManager(self.ui, task_list) |
| task_manager.Run() |