• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
6import logging, os
7import math
8from autotest_lib.client.bin import utils, test
9from autotest_lib.client.common_lib import error
10
11
12class 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        # Get all accelerometer data
151        accel_info = utils.system_output('ectool motionsense')
152        info = accel_info.splitlines()
153
154        # If the base accelerometer is present, then verify data
155        if 'None' not in info[1]:
156            self._verify_accel_data(self._ACCEL_BASE_LOC)
157
158        # If the lid accelerometer is present, then verify data
159        if 'None' not in info[2]:
160            self._verify_accel_data(self._ACCEL_LID_LOC)
161