Convert cacheinvalidation_unittests to run exclusively on Swarming
[chromium-blink-merge.git] / chromeos / accelerometer / accelerometer_reader.cc
blobb238e756302ef52ca5f63c0349a633161887363d
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.
5 #include "chromeos/accelerometer/accelerometer_reader.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/files/file_util.h"
11 #include "base/location.h"
12 #include "base/memory/singleton.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/task_runner.h"
18 #include "base/task_runner_util.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/threading/sequenced_worker_pool.h"
23 namespace chromeos {
25 namespace {
27 // Paths to access necessary data from the accelerometer device.
28 const base::FilePath::CharType kAccelerometerTriggerPath[] =
29 FILE_PATH_LITERAL("/sys/bus/iio/devices/trigger0/trigger_now");
30 const base::FilePath::CharType kAccelerometerDevicePath[] =
31 FILE_PATH_LITERAL("/dev/cros-ec-accel");
32 const base::FilePath::CharType kAccelerometerIioBasePath[] =
33 FILE_PATH_LITERAL("/sys/bus/iio/devices/");
35 // File within the device in kAccelerometerIioBasePath containing the scale of
36 // the accelerometers.
37 const base::FilePath::CharType kScaleNameFormatString[] = "in_accel_%s_scale";
39 // The filename giving the path to read the scan index of each accelerometer
40 // axis.
41 const char kAccelerometerScanIndexPath[] =
42 "scan_elements/in_accel_%s_%s_index";
44 // The names of the accelerometers. Matches up with the enum AccelerometerSource
45 // in chromeos/accelerometer/accelerometer_types.h.
46 const char kAccelerometerNames[ACCELEROMETER_SOURCE_COUNT][5] = {"lid", "base"};
48 // The axes on each accelerometer.
49 const char kAccelerometerAxes[][2] = {"y", "x", "z"};
51 // The length required to read uint values from configuration files.
52 const size_t kMaxAsciiUintLength = 21;
54 // The size of individual values.
55 const size_t kDataSize = 2;
57 // The mean acceleration due to gravity on Earth in m/s^2.
58 const float kMeanGravity = 9.80665f;
60 // The number of accelerometers.
61 const int kNumberOfAccelerometers = 2;
63 // The number of axes for which there are acceleration readings.
64 const int kNumberOfAxes = 3;
66 // The size of data in one reading of the accelerometers.
67 const int kSizeOfReading = kDataSize * kNumberOfAccelerometers * kNumberOfAxes;
69 // Reads |path| to the unsigned int pointed to by |value|. Returns true on
70 // success or false on failure.
71 bool ReadFileToInt(const base::FilePath& path, int* value) {
72 std::string s;
73 DCHECK(value);
74 if (!base::ReadFileToString(path, &s, kMaxAsciiUintLength)) {
75 return false;
77 base::TrimWhitespaceASCII(s, base::TRIM_ALL, &s);
78 if (!base::StringToInt(s, value)) {
79 LOG(ERROR) << "Failed to parse \"" << s << "\" from " << path.value();
80 return false;
82 return true;
85 } // namespace
87 const int AccelerometerReader::kDelayBetweenReadsMs = 100;
89 // Work that runs on a base::TaskRunner. It determines the accelerometer
90 // configuartion, and reads the data. Upon a successful read it will notify
91 // all observers.
92 class AccelerometerFileReader
93 : public base::RefCountedThreadSafe<AccelerometerFileReader> {
94 public:
95 AccelerometerFileReader();
97 // Detects the accelerometer configuration, if an accelerometer is available
98 // triggers reads.
99 void Initialize(
100 scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner);
102 // Attempts to read the accelerometer data. Upon a success, converts the raw
103 // reading to an AccelerometerUpdate and notifies observers. Triggers another
104 // read at the current sampling rate.
105 void Read();
107 // Add/Remove observers.
108 void AddObserver(AccelerometerReader::Observer* observer);
109 void RemoveObserver(AccelerometerReader::Observer* observer);
111 private:
112 friend class base::RefCountedThreadSafe<AccelerometerFileReader>;
114 // Configuration structure for accelerometer device.
115 struct ConfigurationData {
116 ConfigurationData();
117 ~ConfigurationData();
119 // Number of accelerometers on device.
120 size_t count;
122 // Length of accelerometer updates.
123 size_t length;
125 // Which accelerometers are present on device.
126 bool has[ACCELEROMETER_SOURCE_COUNT];
128 // Scale of accelerometers (i.e. raw value * scale = m/s^2).
129 float scale[ACCELEROMETER_SOURCE_COUNT][3];
131 // Index of each accelerometer axis in data stream.
132 int index[ACCELEROMETER_SOURCE_COUNT][3];
135 ~AccelerometerFileReader() {}
137 // Attempts to read the accelerometer data. Upon a success, converts the raw
138 // reading to an AccelerometerUpdate and notifies observers.
139 void ReadFileAndNotify();
141 // True if Initialize completed successfully, and there is an accelerometer
142 // file to read.
143 bool initialization_successful_;
145 // The accelerometer configuration.
146 ConfigurationData configuration_;
148 // The observers to notify of accelerometer updates.
149 scoped_refptr<base::ObserverListThreadSafe<AccelerometerReader::Observer>>
150 observers_;
152 // The task runner to use for blocking tasks.
153 scoped_refptr<base::SequencedTaskRunner> task_runner_;
155 // The last seen accelerometer data.
156 scoped_refptr<AccelerometerUpdate> update_;
158 DISALLOW_COPY_AND_ASSIGN(AccelerometerFileReader);
161 AccelerometerFileReader::AccelerometerFileReader()
162 : initialization_successful_(false),
163 observers_(
164 new base::ObserverListThreadSafe<AccelerometerReader::Observer>()) {
167 void AccelerometerFileReader::Initialize(
168 scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) {
169 DCHECK(
170 base::SequencedWorkerPool::GetSequenceTokenForCurrentThread().IsValid());
171 task_runner_ = sequenced_task_runner;
173 // Check for accelerometer symlink which will be created by the udev rules
174 // file on detecting the device.
175 base::FilePath device;
176 if (!base::ReadSymbolicLink(base::FilePath(kAccelerometerDevicePath),
177 &device)) {
178 return;
181 if (!base::PathExists(base::FilePath(kAccelerometerTriggerPath))) {
182 LOG(ERROR) << "Accelerometer trigger does not exist at"
183 << kAccelerometerTriggerPath;
184 return;
187 base::FilePath iio_path(base::FilePath(kAccelerometerIioBasePath).Append(
188 device));
189 // Read configuration of each accelerometer axis from each accelerometer from
190 // /sys/bus/iio/devices/iio:deviceX/.
191 for (size_t i = 0; i < arraysize(kAccelerometerNames); ++i) {
192 // Read scale of accelerometer.
193 std::string accelerometer_scale_path = base::StringPrintf(
194 kScaleNameFormatString, kAccelerometerNames[i]);
195 int scale_divisor;
196 if (!ReadFileToInt(iio_path.Append(accelerometer_scale_path.c_str()),
197 &scale_divisor)) {
198 configuration_.has[i] = false;
199 continue;
202 configuration_.has[i] = true;
203 configuration_.count++;
204 for (size_t j = 0; j < arraysize(kAccelerometerAxes); ++j) {
205 configuration_.scale[i][j] = kMeanGravity / scale_divisor;
206 std::string accelerometer_index_path = base::StringPrintf(
207 kAccelerometerScanIndexPath, kAccelerometerAxes[j],
208 kAccelerometerNames[i]);
209 if (!ReadFileToInt(iio_path.Append(accelerometer_index_path.c_str()),
210 &(configuration_.index[i][j]))) {
211 return;
216 // Adjust the directions of accelerometers to match the AccelerometerUpdate
217 // type specified in chromeos/accelerometer/accelerometer_types.h.
218 configuration_.scale[ACCELEROMETER_SOURCE_SCREEN][0] *= -1.0f;
219 for (int i = 0; i < 3; ++i) {
220 configuration_.scale[ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD][i] *= -1.0f;
223 // Verify indices are within bounds.
224 for (int i = 0; i < ACCELEROMETER_SOURCE_COUNT; ++i) {
225 if (!configuration_.has[i])
226 continue;
227 for (int j = 0; j < 3; ++j) {
228 if (configuration_.index[i][j] < 0 ||
229 configuration_.index[i][j] >=
230 3 * static_cast<int>(configuration_.count)) {
231 LOG(ERROR) << "Field index for " << kAccelerometerNames[i] << " "
232 << kAccelerometerAxes[j] << " axis out of bounds.";
233 return;
237 configuration_.length = kDataSize * 3 * configuration_.count;
238 initialization_successful_ = true;
239 Read();
242 void AccelerometerFileReader::Read() {
243 DCHECK(
244 base::SequencedWorkerPool::GetSequenceTokenForCurrentThread().IsValid());
245 ReadFileAndNotify();
246 task_runner_->PostNonNestableDelayedTask(
247 FROM_HERE, base::Bind(&AccelerometerFileReader::Read, this),
248 base::TimeDelta::FromMilliseconds(
249 AccelerometerReader::kDelayBetweenReadsMs));
252 void AccelerometerFileReader::AddObserver(
253 AccelerometerReader::Observer* observer) {
254 observers_->AddObserver(observer);
255 if (initialization_successful_) {
256 task_runner_->PostNonNestableTask(
257 FROM_HERE,
258 base::Bind(&AccelerometerFileReader::ReadFileAndNotify, this));
262 void AccelerometerFileReader::RemoveObserver(
263 AccelerometerReader::Observer* observer) {
264 observers_->RemoveObserver(observer);
267 void AccelerometerFileReader::ReadFileAndNotify() {
268 DCHECK(initialization_successful_);
269 char reading[kSizeOfReading];
271 // Initiate the trigger to read accelerometers simultaneously
272 int bytes_written = base::WriteFile(
273 base::FilePath(kAccelerometerTriggerPath), "1\n", 2);
274 if (bytes_written < 2) {
275 PLOG(ERROR) << "Accelerometer trigger failure: " << bytes_written;
276 return;
279 // Read resulting sample from /dev/cros-ec-accel.
280 int bytes_read = base::ReadFile(base::FilePath(kAccelerometerDevicePath),
281 reading, configuration_.length);
282 if (bytes_read < static_cast<int>(configuration_.length)) {
283 LOG(ERROR) << "Read " << bytes_read << " byte(s), expected "
284 << configuration_.length << " bytes from accelerometer";
285 return;
288 update_ = new AccelerometerUpdate();
290 for (int i = 0; i < ACCELEROMETER_SOURCE_COUNT; ++i) {
291 if (!configuration_.has[i])
292 continue;
294 int16* values = reinterpret_cast<int16*>(reading);
295 update_->Set(
296 static_cast<AccelerometerSource>(i),
297 values[configuration_.index[i][0]] * configuration_.scale[i][0],
298 values[configuration_.index[i][1]] * configuration_.scale[i][1],
299 values[configuration_.index[i][2]] * configuration_.scale[i][2]);
302 observers_->Notify(FROM_HERE,
303 &AccelerometerReader::Observer::OnAccelerometerUpdated,
304 update_);
307 AccelerometerFileReader::ConfigurationData::ConfigurationData() : count(0) {
308 for (int i = 0; i < ACCELEROMETER_SOURCE_COUNT; ++i) {
309 has[i] = false;
310 for (int j = 0; j < 3; ++j) {
311 scale[i][j] = 0;
312 index[i][j] = -1;
317 AccelerometerFileReader::ConfigurationData::~ConfigurationData() {
320 // static
321 AccelerometerReader* AccelerometerReader::GetInstance() {
322 return Singleton<AccelerometerReader>::get();
325 void AccelerometerReader::Initialize(
326 scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) {
327 DCHECK(sequenced_task_runner.get());
328 // Asynchronously detect and initialize the accelerometer to avoid delaying
329 // startup.
330 sequenced_task_runner->PostNonNestableTask(
331 FROM_HERE,
332 base::Bind(&AccelerometerFileReader::Initialize,
333 accelerometer_file_reader_.get(), sequenced_task_runner));
336 void AccelerometerReader::AddObserver(Observer* observer) {
337 accelerometer_file_reader_->AddObserver(observer);
340 void AccelerometerReader::RemoveObserver(Observer* observer) {
341 accelerometer_file_reader_->RemoveObserver(observer);
344 AccelerometerReader::AccelerometerReader()
345 : accelerometer_file_reader_(new AccelerometerFileReader()) {
348 AccelerometerReader::~AccelerometerReader() {
351 } // namespace chromeos