Home | History | Annotate | Download | only in kernel_CrosECSysfsAccel
      1 # Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 
      6 import logging, os
      7 import math
      8 from autotest_lib.client.bin import utils, test
      9 from autotest_lib.client.common_lib import error
     10 
     11 
     12 class kernel_CrosECSysfsAccel(test.test):
     13     '''Make sure the EC sysfs accel interface provides meaningful output'''
     14     version = 1
     15 
     16 
     17     # For EC accelerometer, define the number of counts in 1G, and the number
     18     # of counts that the magnitude of each sensor is allowed to be off from a
     19     # magnitude of 1G. These values are not sensor dependent, they are based
     20     # on the EC sysfs interface, which specifies number of counts in 1G.
     21     _ACCEL_1G_IN_G = 1024
     22     _ACCEL_1G_IN_MS2 = 9.8185
     23     _ACCEL_MAG_VALID_OFFSET = .25
     24 
     25     _ACCEL_BASE_LOC = 'base'
     26     _ACCEL_LID_LOC = 'lid'
     27     _ACCEL_LOCS = [_ACCEL_BASE_LOC, _ACCEL_LID_LOC]
     28 
     29 
     30     sysfs_accel_search_path = '/sys/bus/iio/devices'
     31     sysfs_accel_paths = {}
     32     sysfs_accel_old_path = ''
     33     new_sysfs_layout = True
     34 
     35     @classmethod
     36     def _read_sysfs_accel_file(cls, fullpath):
     37         """
     38         Read the contents of the given accel sysfs file or fail
     39 
     40         @param fullpath Name of the file within the accel sysfs interface
     41         directory
     42         """
     43         try:
     44             content = utils.read_file(fullpath)
     45         except Exception as err:
     46             raise error.TestFail('sysfs file problem: %s' % err)
     47         return content
     48 
     49 
     50     def _find_sysfs_accel_dir(self):
     51         """
     52         Return the sysfs directory for accessing EC accels
     53         """
     54         for _, dirs, _ in os.walk(self.sysfs_accel_search_path):
     55             for d in dirs:
     56                 dirpath = os.path.join(self.sysfs_accel_search_path, d)
     57                 namepath = os.path.join(dirpath, 'name')
     58 
     59                 try:
     60                     content = utils.read_file(namepath)
     61                 except IOError as err:
     62                     # errno 2 is code for file does not exist, which is ok
     63                     # here, just continue on to next directory. Any other
     64                     # error is a problem, raise an error.
     65                     if err.errno == 2:
     66                         continue
     67                     raise error.TestFail('IOError %d while searching for accel'
     68                                          'sysfs dir in %s', err.errno, namepath)
     69 
     70                 # Correct directory has a file called 'name' with contents
     71                 # 'cros-ec-accel'
     72                 if content.strip() != 'cros-ec-accel':
     73                     continue
     74 
     75                 locpath = os.path.join(dirpath, 'location')
     76                 try:
     77                     location = utils.read_file(locpath)
     78                 except IOError as err:
     79                     if err.errno == 2:
     80                         # We have an older scheme
     81                         self.new_sysfs_layout = False
     82                         self.sysfs_accel_old_path = dirpath
     83                         return
     84                     raise error.TestFail('IOError %d while reading %s',
     85                                          err.errno, locpath)
     86                 loc = location.strip()
     87                 if loc in self._ACCEL_LOCS:
     88                     self.sysfs_accel_paths[loc] = dirpath
     89 
     90         if (not self.sysfs_accel_old_path and
     91             len(self.sysfs_accel_paths) == 0):
     92             raise error.TestFail('No sysfs interface to EC accels (cros-ec-accel)')
     93 
     94     def _verify_accel_data(self, name):
     95         """
     96         Verify one of the EC accelerometers through the sysfs interface.
     97         """
     98         if self.new_sysfs_layout:
     99             accel_scale = float(self._read_sysfs_accel_file(
    100                 os.path.join(self.sysfs_accel_paths[name],
    101                              'scale')))
    102             exp = self._ACCEL_1G_IN_MS2
    103         else:
    104             accel_scale = 1
    105             exp = self._ACCEL_1G_IN_G
    106 
    107         err = exp * self._ACCEL_MAG_VALID_OFFSET
    108         value = {}
    109         mag = 0
    110         for axis in ['x', 'y', 'z']:
    111             name_list = ['in', 'accel', axis]
    112             if self.new_sysfs_layout:
    113                 base_path = self.sysfs_accel_paths[name]
    114             else:
    115                 base_path = self.sysfs_accel_old_path
    116                 name_list.append(name)
    117             name_list.append('raw')
    118             axis_path = os.path.join(base_path, '_'.join(name_list))
    119             value[axis] = int(self._read_sysfs_accel_file(axis_path))
    120             value[axis] *= accel_scale
    121             mag += value[axis] * value[axis]
    122 
    123         mag = math.sqrt(mag)
    124 
    125         # Accel data is out of range if magnitude is not close to 1G.
    126         # Note, this means test will fail on the moon.
    127         if abs(mag - exp) <= err:
    128             logging.info("%s accel passed. Magnitude is %f.", name, mag)
    129         else:
    130             logging.info("%s accel bad data. Magnitude is %f, expected "
    131                          "%f +/-%f. Raw data is x:%f, y:%f, z:%f.", name,
    132                          mag, exp, err, value['x'], value['y'], value['z'])
    133             raise error.TestFail("Accel magnitude out of range.")
    134 
    135 
    136     def run_once(self):
    137         """
    138         Check for accelerometers, and if present, check data is valid
    139         """
    140         # First make sure that the motion sensors are active. If this
    141         # check fails it means the EC motion sense task is not running and
    142         # therefore not updating acceleration values in shared memory.
    143         active = utils.system_output('ectool motionsense active')
    144         if active == "0":
    145             raise error.TestFail("Motion sensing is inactive")
    146 
    147         # Find the iio sysfs directory for EC accels
    148         self._find_sysfs_accel_dir()
    149 
    150         if self.sysfs_accel_old_path:
    151             # Get all accelerometer data
    152             accel_info = utils.system_output('ectool motionsense')
    153             info = accel_info.splitlines()
    154 
    155             # If the base accelerometer is present, then verify data
    156             if 'None' not in info[1]:
    157                 self._verify_accel_data(self._ACCEL_BASE_LOC)
    158 
    159             # If the lid accelerometer is present, then verify data
    160             if 'None' not in info[2]:
    161                 self._verify_accel_data(self._ACCEL_LID_LOC)
    162         else:
    163             for loc in self.sysfs_accel_paths.keys():
    164                 self._verify_accel_data(loc)
    165