Home | History | Annotate | Download | only in accelerometer
      1 // Copyright 2014 The Chromium 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 #include "chromeos/accelerometer/accelerometer_reader.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/files/file_util.h"
      9 #include "base/location.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/task_runner.h"
     15 #include "base/task_runner_util.h"
     16 #include "base/threading/sequenced_worker_pool.h"
     17 
     18 namespace chromeos {
     19 
     20 namespace {
     21 
     22 // Paths to access necessary data from the accelerometer device.
     23 const base::FilePath::CharType kAccelerometerTriggerPath[] =
     24     FILE_PATH_LITERAL("/sys/bus/iio/devices/trigger0/trigger_now");
     25 const base::FilePath::CharType kAccelerometerDevicePath[] =
     26     FILE_PATH_LITERAL("/dev/cros-ec-accel");
     27 const base::FilePath::CharType kAccelerometerIioBasePath[] =
     28     FILE_PATH_LITERAL("/sys/bus/iio/devices/");
     29 
     30 // File within the device in kAccelerometerIioBasePath containing the scale of
     31 // the accelerometers.
     32 const base::FilePath::CharType kScaleNameFormatString[] = "in_accel_%s_scale";
     33 
     34 // The filename giving the path to read the scan index of each accelerometer
     35 // axis.
     36 const char kAccelerometerScanIndexPath[] =
     37     "scan_elements/in_accel_%s_%s_index";
     38 
     39 // The names of the accelerometers. Matches up with the enum AccelerometerSource
     40 // in ui/accelerometer/accelerometer_types.h.
     41 const char kAccelerometerNames[ui::ACCELEROMETER_SOURCE_COUNT][5] = {
     42     "lid", "base"};
     43 
     44 // The axes on each accelerometer.
     45 const char kAccelerometerAxes[][2] = {"y", "x", "z"};
     46 
     47 // The length required to read uint values from configuration files.
     48 const size_t kMaxAsciiUintLength = 21;
     49 
     50 // The size of individual values.
     51 const size_t kDataSize = 2;
     52 
     53 // The time to wait between reading the accelerometer.
     54 const int kDelayBetweenReadsMs = 100;
     55 
     56 // The mean acceleration due to gravity on Earth in m/s^2.
     57 const float kMeanGravity = 9.80665f;
     58 
     59 // Reads |path| to the unsigned int pointed to by |value|. Returns true on
     60 // success or false on failure.
     61 bool ReadFileToInt(const base::FilePath& path, int* value) {
     62   std::string s;
     63   DCHECK(value);
     64   if (!base::ReadFileToString(path, &s, kMaxAsciiUintLength)) {
     65     return false;
     66   }
     67   base::TrimWhitespaceASCII(s, base::TRIM_ALL, &s);
     68   if (!base::StringToInt(s, value)) {
     69     LOG(ERROR) << "Failed to parse \"" << s << "\" from " << path.value();
     70     return false;
     71   }
     72   return true;
     73 }
     74 
     75 bool DetectAndReadAccelerometerConfiguration(
     76     scoped_refptr<AccelerometerReader::Configuration> configuration) {
     77   // Check for accelerometer symlink which will be created by the udev rules
     78   // file on detecting the device.
     79   base::FilePath device;
     80   if (!base::ReadSymbolicLink(base::FilePath(kAccelerometerDevicePath),
     81                               &device)) {
     82     return false;
     83   }
     84 
     85   if (!base::PathExists(base::FilePath(kAccelerometerTriggerPath))) {
     86     LOG(ERROR) << "Accelerometer trigger does not exist at"
     87                << kAccelerometerTriggerPath;
     88     return false;
     89   }
     90 
     91   base::FilePath iio_path(base::FilePath(kAccelerometerIioBasePath).Append(
     92       device));
     93   // Read configuration of each accelerometer axis from each accelerometer from
     94   // /sys/bus/iio/devices/iio:deviceX/.
     95   for (size_t i = 0; i < arraysize(kAccelerometerNames); ++i) {
     96     // Read scale of accelerometer.
     97     std::string accelerometer_scale_path = base::StringPrintf(
     98         kScaleNameFormatString, kAccelerometerNames[i]);
     99     int scale_divisor;
    100     if (!ReadFileToInt(iio_path.Append(accelerometer_scale_path.c_str()),
    101         &scale_divisor)) {
    102       configuration->data.has[i] = false;
    103       continue;
    104     }
    105 
    106     configuration->data.has[i] = true;
    107     configuration->data.count++;
    108     for (size_t j = 0; j < arraysize(kAccelerometerAxes); ++j) {
    109       configuration->data.scale[i][j] = kMeanGravity / scale_divisor;
    110       std::string accelerometer_index_path = base::StringPrintf(
    111           kAccelerometerScanIndexPath, kAccelerometerAxes[j],
    112           kAccelerometerNames[i]);
    113       if (!ReadFileToInt(iio_path.Append(accelerometer_index_path.c_str()),
    114                          &(configuration->data.index[i][j]))) {
    115         return false;
    116       }
    117     }
    118   }
    119 
    120   // Adjust the directions of accelerometers to match the AccelerometerUpdate
    121   // type specified in ui/accelerometer/accelerometer_types.h.
    122   configuration->data.scale[ui::ACCELEROMETER_SOURCE_SCREEN][0] *= -1.0f;
    123   for (int i = 0; i < 3; ++i) {
    124     configuration->data.scale[ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD][i] *=
    125         -1.0f;
    126   }
    127 
    128   // Verify indices are within bounds.
    129   for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) {
    130     if (!configuration->data.has[i])
    131       continue;
    132     for (int j = 0; j < 3; ++j) {
    133       if (configuration->data.index[i][j] < 0 ||
    134           configuration->data.index[i][j] >=
    135               3 * static_cast<int>(configuration->data.count)) {
    136         LOG(ERROR) << "Field index for " << kAccelerometerNames[i] << " "
    137                    << kAccelerometerAxes[j] << " axis out of bounds.";
    138         return false;
    139       }
    140     }
    141   }
    142   configuration->data.length = kDataSize * 3 * configuration->data.count;
    143   return true;
    144 }
    145 
    146 bool ReadAccelerometer(
    147     scoped_refptr<AccelerometerReader::Reading> reading,
    148     size_t length) {
    149   // Initiate the trigger to read accelerometers simultaneously
    150   int bytes_written = base::WriteFile(
    151       base::FilePath(kAccelerometerTriggerPath), "1\n", 2);
    152   if (bytes_written < 2) {
    153     PLOG(ERROR) << "Accelerometer trigger failure: " << bytes_written;
    154     return false;
    155   }
    156 
    157   // Read resulting sample from /dev/cros-ec-accel.
    158   int bytes_read = base::ReadFile(base::FilePath(kAccelerometerDevicePath),
    159                                   reading->data, length);
    160   if (bytes_read < static_cast<int>(length)) {
    161     LOG(ERROR) << "Read " << bytes_read << " byte(s), expected "
    162                << length << " bytes from accelerometer";
    163     return false;
    164   }
    165   return true;
    166 }
    167 
    168 }  // namespace
    169 
    170 AccelerometerReader::ConfigurationData::ConfigurationData()
    171     : count(0) {
    172   for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) {
    173     has[i] = false;
    174     for (int j = 0; j < 3; ++j) {
    175       scale[i][j] = 0;
    176       index[i][j] = -1;
    177     }
    178   }
    179 }
    180 
    181 AccelerometerReader::ConfigurationData::~ConfigurationData() {
    182 }
    183 
    184 AccelerometerReader::AccelerometerReader(
    185     scoped_refptr<base::TaskRunner> blocking_task_runner,
    186     AccelerometerReader::Delegate* delegate)
    187     : task_runner_(blocking_task_runner),
    188       delegate_(delegate),
    189       configuration_(new AccelerometerReader::Configuration()),
    190       weak_factory_(this) {
    191   DCHECK(task_runner_.get());
    192   DCHECK(delegate_);
    193   // Asynchronously detect and initialize the accelerometer to avoid delaying
    194   // startup.
    195   base::PostTaskAndReplyWithResult(task_runner_.get(), FROM_HERE,
    196       base::Bind(&DetectAndReadAccelerometerConfiguration, configuration_),
    197       base::Bind(&AccelerometerReader::OnInitialized,
    198                  weak_factory_.GetWeakPtr(), configuration_));
    199 }
    200 
    201 AccelerometerReader::~AccelerometerReader() {
    202 }
    203 
    204 void AccelerometerReader::OnInitialized(
    205     scoped_refptr<AccelerometerReader::Configuration> configuration,
    206     bool success) {
    207   if (success)
    208     TriggerRead();
    209 }
    210 
    211 void AccelerometerReader::TriggerRead() {
    212   DCHECK(!task_runner_->RunsTasksOnCurrentThread());
    213 
    214   scoped_refptr<AccelerometerReader::Reading> reading(
    215       new AccelerometerReader::Reading());
    216   base::PostTaskAndReplyWithResult(task_runner_.get(),
    217                                    FROM_HERE,
    218                                    base::Bind(&ReadAccelerometer, reading,
    219                                               configuration_->data.length),
    220                                    base::Bind(&AccelerometerReader::OnDataRead,
    221                                               weak_factory_.GetWeakPtr(),
    222                                               reading));
    223 }
    224 
    225 void AccelerometerReader::OnDataRead(
    226     scoped_refptr<AccelerometerReader::Reading> reading,
    227     bool success) {
    228   DCHECK(!task_runner_->RunsTasksOnCurrentThread());
    229 
    230   if (success) {
    231     for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) {
    232       if (!configuration_->data.has[i])
    233         continue;
    234 
    235       int16* values = reinterpret_cast<int16*>(reading->data);
    236       update_.Set(static_cast<ui::AccelerometerSource>(i),
    237                   values[configuration_->data.index[i][0]] *
    238                       configuration_->data.scale[i][0],
    239                   values[configuration_->data.index[i][1]] *
    240                       configuration_->data.scale[i][1],
    241                   values[configuration_->data.index[i][2]] *
    242                       configuration_->data.scale[i][2]);
    243     }
    244     delegate_->HandleAccelerometerUpdate(update_);
    245   }
    246 
    247   // Trigger another read after the current sampling delay.
    248   base::MessageLoop::current()->PostDelayedTask(
    249       FROM_HERE,
    250       base::Bind(&AccelerometerReader::TriggerRead,
    251                  weak_factory_.GetWeakPtr()),
    252       base::TimeDelta::FromMilliseconds(kDelayBetweenReadsMs));
    253 }
    254 
    255 }  // namespace chromeos
    256