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)
|