b08494d31e7a5e32fde42f4aca068f8bd7983076
[platform/framework/web/crosswalk.git] / src / chromeos / accelerometer / accelerometer_reader.cc
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