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/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 // Files within the device in kAccelerometerIioBasePath containing the scales of
     31 // the accelerometers.
     32 const base::FilePath::CharType kAccelerometerBaseScaleName[] =
     33     FILE_PATH_LITERAL("in_accel_base_scale");
     34 const base::FilePath::CharType kAccelerometerLidScaleName[] =
     35     FILE_PATH_LITERAL("in_accel_lid_scale");
     36 
     37 // The filename giving the path to read the scan index of each accelerometer
     38 // axis.
     39 const char kAccelerometerScanIndexPath[] =
     40     "scan_elements/in_accel_%s_%s_index";
     41 
     42 // The names of the accelerometers and axes in the order we want to read them.
     43 const char kAccelerometerNames[][5] = {"base", "lid"};
     44 const char kAccelerometerAxes[][2] = {"x", "y", "z"};
     45 const size_t kTriggerDataValues =
     46     arraysize(kAccelerometerNames) * arraysize(kAccelerometerAxes);
     47 const size_t kTriggerDataLength = kTriggerDataValues * 2;
     48 
     49 // The length required to read uint values from configuration files.
     50 const size_t kMaxAsciiUintLength = 21;
     51 
     52 // The time to wait between reading the accelerometer.
     53 const int kDelayBetweenReadsMs = 100;
     54 
     55 // Reads |path| to the unsigned int pointed to by |value|. Returns true on
     56 // success or false on failure.
     57 bool ReadFileToUint(const base::FilePath& path, unsigned int* value) {
     58   std::string s;
     59   DCHECK(value);
     60   if (!base::ReadFileToString(path, &s, kMaxAsciiUintLength)) {
     61     LOG(ERROR) << "Failed to read " << path.value();
     62     return false;
     63   }
     64   base::TrimWhitespaceASCII(s, base::TRIM_ALL, &s);
     65   if (!base::StringToUint(s, value)) {
     66     LOG(ERROR) << "Failed to parse \"" << s << "\" from " << path.value();
     67     return false;
     68   }
     69   return true;
     70 }
     71 
     72 bool DetectAndReadAccelerometerConfiguration(
     73     scoped_refptr<AccelerometerReader::Configuration> configuration) {
     74   // Check for accelerometer symlink which will be created by the udev rules
     75   // file on detecting the device.
     76   base::FilePath device;
     77   if (!base::ReadSymbolicLink(base::FilePath(kAccelerometerDevicePath),
     78                               &device)) {
     79     return false;
     80   }
     81 
     82   if (!base::PathExists(base::FilePath(kAccelerometerTriggerPath))) {
     83     LOG(ERROR) << "Accelerometer trigger does not exist at"
     84                << kAccelerometerTriggerPath;
     85     return false;
     86   }
     87 
     88   base::FilePath iio_path(base::FilePath(kAccelerometerIioBasePath).Append(
     89       device));
     90   // Read accelerometer scales
     91   if (!ReadFileToUint(iio_path.Append(kAccelerometerBaseScaleName),
     92                       &(configuration->data.base_scale))) {
     93     return false;
     94   }
     95   if (!ReadFileToUint(iio_path.Append(kAccelerometerLidScaleName),
     96                       &(configuration->data.lid_scale))) {
     97     return false;
     98   }
     99 
    100   // Read indices of each accelerometer axis from each accelerometer from
    101   // /sys/bus/iio/devices/iio:deviceX/scan_elements/in_accel_{x,y,z}_%s_index
    102   for (size_t i = 0; i < arraysize(kAccelerometerNames); ++i) {
    103     for (size_t j = 0; j < arraysize(kAccelerometerAxes); ++j) {
    104       std::string accelerometer_index_path = base::StringPrintf(
    105           kAccelerometerScanIndexPath, kAccelerometerAxes[j],
    106           kAccelerometerNames[i]);
    107       unsigned int index = 0;
    108       if (!ReadFileToUint(iio_path.Append(accelerometer_index_path.c_str()),
    109                           &index)) {
    110         return false;
    111       }
    112       if (index >= kTriggerDataValues) {
    113         LOG(ERROR) << "Field index from " << accelerometer_index_path
    114                    << " out of bounds: " << index;
    115         return false;
    116       }
    117       configuration->data.index.push_back(index);
    118     }
    119   }
    120   return true;
    121 }
    122 
    123 bool ReadAccelerometer(
    124     scoped_refptr<AccelerometerReader::Reading> reading) {
    125   // Initiate the trigger to read accelerometers simultaneously
    126   int bytes_written = base::WriteFile(
    127       base::FilePath(kAccelerometerTriggerPath), "1\n", 2);
    128   if (bytes_written < 2) {
    129     PLOG(ERROR) << "Accelerometer trigger failure: " << bytes_written;
    130     return false;
    131   }
    132 
    133   // Read resulting sample from /dev/cros-ec-accel.
    134   int bytes_read = base::ReadFile(base::FilePath(kAccelerometerDevicePath),
    135                                   reading->data, kTriggerDataLength);
    136   if (bytes_read < static_cast<int>(kTriggerDataLength)) {
    137     LOG(ERROR) << "Read " << bytes_read << " byte(s), expected "
    138                << kTriggerDataLength << " bytes from accelerometer";
    139     return false;
    140   }
    141   return true;
    142 }
    143 
    144 }  // namespace
    145 
    146 AccelerometerReader::ConfigurationData::ConfigurationData() {
    147 }
    148 
    149 AccelerometerReader::ConfigurationData::~ConfigurationData() {
    150 }
    151 
    152 AccelerometerReader::AccelerometerReader(
    153     base::TaskRunner* task_runner,
    154     AccelerometerReader::Delegate* delegate)
    155     : task_runner_(task_runner),
    156       delegate_(delegate),
    157       configuration_(new AccelerometerReader::Configuration()),
    158       weak_factory_(this) {
    159   DCHECK(task_runner_);
    160   DCHECK(delegate_);
    161   // Asynchronously detect and initialize the accelerometer to avoid delaying
    162   // startup.
    163   base::PostTaskAndReplyWithResult(task_runner_.get(), FROM_HERE,
    164       base::Bind(&DetectAndReadAccelerometerConfiguration, configuration_),
    165       base::Bind(&AccelerometerReader::OnInitialized,
    166                  weak_factory_.GetWeakPtr(), configuration_));
    167 }
    168 
    169 AccelerometerReader::~AccelerometerReader() {
    170 }
    171 
    172 void AccelerometerReader::OnInitialized(
    173     scoped_refptr<AccelerometerReader::Configuration> configuration,
    174     bool success) {
    175   if (success)
    176     TriggerRead();
    177 }
    178 
    179 void AccelerometerReader::TriggerRead() {
    180   DCHECK(!task_runner_->RunsTasksOnCurrentThread());
    181 
    182   scoped_refptr<AccelerometerReader::Reading> reading(
    183       new AccelerometerReader::Reading());
    184   base::PostTaskAndReplyWithResult(task_runner_, FROM_HERE,
    185       base::Bind(&ReadAccelerometer, reading),
    186       base::Bind(&AccelerometerReader::OnDataRead,
    187           weak_factory_.GetWeakPtr(), reading));
    188 }
    189 
    190 void AccelerometerReader::OnDataRead(
    191     scoped_refptr<AccelerometerReader::Reading> reading,
    192     bool success) {
    193   DCHECK(!task_runner_->RunsTasksOnCurrentThread());
    194 
    195   if (success) {
    196     gfx::Vector3dF base_reading, lid_reading;
    197     int16* values = reinterpret_cast<int16*>(reading->data);
    198     base_reading.set_x(values[configuration_->data.index[0]]);
    199     base_reading.set_y(values[configuration_->data.index[1]]);
    200     base_reading.set_z(values[configuration_->data.index[2]]);
    201     base_reading.Scale(1.0f / configuration_->data.base_scale);
    202 
    203     lid_reading.set_x(values[configuration_->data.index[3]]);
    204     lid_reading.set_y(values[configuration_->data.index[4]]);
    205     lid_reading.set_z(values[configuration_->data.index[5]]);
    206     lid_reading.Scale(1.0f / configuration_->data.lid_scale);
    207     delegate_->HandleAccelerometerReading(base_reading, lid_reading);
    208   }
    209 
    210   // Trigger another read after the current sampling delay.
    211   base::MessageLoop::current()->PostDelayedTask(
    212       FROM_HERE,
    213       base::Bind(&AccelerometerReader::TriggerRead,
    214                  weak_factory_.GetWeakPtr()),
    215       base::TimeDelta::FromMilliseconds(kDelayBetweenReadsMs));
    216 }
    217 
    218 }  // namespace chromeos
    219