168 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			168 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
| # Copyright (c) 2014 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.
 | |
| 
 | |
| 
 | |
| import logging, os
 | |
| import math
 | |
| from autotest_lib.client.bin import utils, test
 | |
| from autotest_lib.client.common_lib import error
 | |
| 
 | |
| 
 | |
| class kernel_CrosECSysfsAccel(test.test):
 | |
|     '''Make sure the EC sysfs accel interface provides meaningful output'''
 | |
|     version = 1
 | |
| 
 | |
| 
 | |
|     # For EC accelerometer, define the number of counts in 1G, and the number
 | |
|     # of counts that the magnitude of each sensor is allowed to be off from a
 | |
|     # magnitude of 1G. These values are not sensor dependent, they are based
 | |
|     # on the EC sysfs interface, which specifies number of counts in 1G.
 | |
|     _ACCEL_1G_IN_G = 1024
 | |
|     _ACCEL_1G_IN_MS2 = 9.8185
 | |
|     _ACCEL_MAG_VALID_OFFSET = .25
 | |
| 
 | |
|     _ACCEL_BASE_LOC = 'base'
 | |
|     _ACCEL_LID_LOC = 'lid'
 | |
|     _ACCEL_LOCS = [_ACCEL_BASE_LOC, _ACCEL_LID_LOC]
 | |
| 
 | |
| 
 | |
|     sysfs_accel_search_path = '/sys/bus/iio/devices'
 | |
|     sysfs_accel_paths = {}
 | |
|     sysfs_accel_old_path = ''
 | |
|     new_sysfs_layout = True
 | |
| 
 | |
|     @classmethod
 | |
|     def _read_sysfs_accel_file(cls, fullpath):
 | |
|         """
 | |
|         Read the contents of the given accel sysfs file or fail
 | |
| 
 | |
|         @param fullpath Name of the file within the accel sysfs interface
 | |
|         directory
 | |
|         """
 | |
|         try:
 | |
|             content = utils.read_file(fullpath)
 | |
|         except Exception as err:
 | |
|             raise error.TestFail('sysfs file problem: %s' % err)
 | |
|         return content
 | |
| 
 | |
| 
 | |
|     def _find_sysfs_accel_dir(self):
 | |
|         """
 | |
|         Return the sysfs directory for accessing EC accels
 | |
|         """
 | |
|         for _, dirs, _ in os.walk(self.sysfs_accel_search_path):
 | |
|             for d in dirs:
 | |
|                 dirpath = os.path.join(self.sysfs_accel_search_path, d)
 | |
|                 namepath = os.path.join(dirpath, 'name')
 | |
| 
 | |
|                 try:
 | |
|                     content = utils.read_file(namepath)
 | |
|                 except IOError as err:
 | |
|                     # errno 2 is code for file does not exist, which is ok
 | |
|                     # here, just continue on to next directory. Any other
 | |
|                     # error is a problem, raise an error.
 | |
|                     if err.errno == 2:
 | |
|                         continue
 | |
|                     raise error.TestFail('IOError %d while searching for accel'
 | |
|                                          'sysfs dir in %s', err.errno, namepath)
 | |
| 
 | |
|                 # Correct directory has a file called 'name' with contents
 | |
|                 # 'cros-ec-accel'
 | |
|                 if content.strip() != 'cros-ec-accel':
 | |
|                     continue
 | |
| 
 | |
|                 locpath = os.path.join(dirpath, 'location')
 | |
|                 try:
 | |
|                     location = utils.read_file(locpath)
 | |
|                 except IOError as err:
 | |
|                     if err.errno == 2:
 | |
|                         # We have an older scheme
 | |
|                         self.new_sysfs_layout = False
 | |
|                         self.sysfs_accel_old_path = dirpath
 | |
|                         return
 | |
|                     raise error.TestFail('IOError %d while reading %s',
 | |
|                                          err.errno, locpath)
 | |
|                 loc = location.strip()
 | |
|                 if loc in self._ACCEL_LOCS:
 | |
|                     self.sysfs_accel_paths[loc] = dirpath
 | |
| 
 | |
|         if (not self.sysfs_accel_old_path and
 | |
|             len(self.sysfs_accel_paths) == 0):
 | |
|             raise error.TestFail('No sysfs interface to EC accels (cros-ec-accel)')
 | |
| 
 | |
|     def _verify_accel_data(self, name):
 | |
|         """
 | |
|         Verify one of the EC accelerometers through the sysfs interface.
 | |
|         """
 | |
|         if self.new_sysfs_layout:
 | |
|             accel_scale = float(self._read_sysfs_accel_file(
 | |
|                 os.path.join(self.sysfs_accel_paths[name],
 | |
|                              'scale')))
 | |
|             exp = self._ACCEL_1G_IN_MS2
 | |
|         else:
 | |
|             accel_scale = 1
 | |
|             exp = self._ACCEL_1G_IN_G
 | |
| 
 | |
|         err = exp * self._ACCEL_MAG_VALID_OFFSET
 | |
|         value = {}
 | |
|         mag = 0
 | |
|         for axis in ['x', 'y', 'z']:
 | |
|             name_list = ['in', 'accel', axis]
 | |
|             if self.new_sysfs_layout:
 | |
|                 base_path = self.sysfs_accel_paths[name]
 | |
|             else:
 | |
|                 base_path = self.sysfs_accel_old_path
 | |
|                 name_list.append(name)
 | |
|             name_list.append('raw')
 | |
|             axis_path = os.path.join(base_path, '_'.join(name_list))
 | |
|             value[axis] = int(self._read_sysfs_accel_file(axis_path))
 | |
|             value[axis] *= accel_scale
 | |
|             mag += value[axis] * value[axis]
 | |
| 
 | |
|         mag = math.sqrt(mag)
 | |
| 
 | |
|         # Accel data is out of range if magnitude is not close to 1G.
 | |
|         # Note, this means test will fail on the moon.
 | |
|         if abs(mag - exp) <= err:
 | |
|             logging.info("%s accel passed. Magnitude is %f.", name, mag)
 | |
|         else:
 | |
|             logging.info("%s accel bad data. Magnitude is %f, expected "
 | |
|                          "%f +/-%f. Raw data is x:%f, y:%f, z:%f.", name,
 | |
|                          mag, exp, err, value['x'], value['y'], value['z'])
 | |
|             raise error.TestFail("Accel magnitude out of range.")
 | |
| 
 | |
| 
 | |
|     def run_once(self):
 | |
|         """
 | |
|         Check for accelerometers, and if present, check data is valid
 | |
|         """
 | |
|         # First make sure that the motion sensors are active. If this
 | |
|         # check fails it means the EC motion sense task is not running and
 | |
|         # therefore not updating acceleration values in shared memory.
 | |
|         # Note that this check only works for x86 boards.
 | |
|         arch = utils.get_arch()
 | |
|         if arch.startswith('x86'):
 | |
|             active = utils.system_output('ectool motionsense active')
 | |
|             if active == "0":
 | |
|                 raise error.TestFail("Motion sensing is inactive")
 | |
| 
 | |
|         # Find the iio sysfs directory for EC accels
 | |
|         self._find_sysfs_accel_dir()
 | |
| 
 | |
|         if self.sysfs_accel_old_path:
 | |
|             # Get all accelerometer data
 | |
|             accel_info = utils.system_output('ectool motionsense')
 | |
|             info = accel_info.splitlines()
 | |
| 
 | |
|             # If the base accelerometer is present, then verify data
 | |
|             if 'None' not in info[1]:
 | |
|                 self._verify_accel_data(self._ACCEL_BASE_LOC)
 | |
| 
 | |
|             # If the lid accelerometer is present, then verify data
 | |
|             if 'None' not in info[2]:
 | |
|                 self._verify_accel_data(self._ACCEL_LID_LOC)
 | |
|         else:
 | |
|             for loc in self.sysfs_accel_paths.keys():
 | |
|                 self._verify_accel_data(loc)
 |