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"
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"
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
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
) {
74 if (!base::ReadFileToString(path
, &s
, kMaxAsciiUintLength
)) {
77 base::TrimWhitespaceASCII(s
, base::TRIM_ALL
, &s
);
78 if (!base::StringToInt(s
, value
)) {
79 LOG(ERROR
) << "Failed to parse \"" << s
<< "\" from " << path
.value();
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
92 class AccelerometerFileReader
93 : public base::RefCountedThreadSafe
<AccelerometerFileReader
> {
95 AccelerometerFileReader();
97 // Detects the accelerometer configuration, if an accelerometer is available
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.
107 // Add/Remove observers.
108 void AddObserver(AccelerometerReader::Observer
* observer
);
109 void RemoveObserver(AccelerometerReader::Observer
* observer
);
112 friend class base::RefCountedThreadSafe
<AccelerometerFileReader
>;
114 // Configuration structure for accelerometer device.
115 struct ConfigurationData
{
117 ~ConfigurationData();
119 // Number of accelerometers on device.
122 // Length of accelerometer updates.
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
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
>>
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),
164 new base::ObserverListThreadSafe
<AccelerometerReader::Observer
>()) {
167 void AccelerometerFileReader::Initialize(
168 scoped_refptr
<base::SequencedTaskRunner
> sequenced_task_runner
) {
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
),
181 if (!base::PathExists(base::FilePath(kAccelerometerTriggerPath
))) {
182 LOG(ERROR
) << "Accelerometer trigger does not exist at"
183 << kAccelerometerTriggerPath
;
187 base::FilePath
iio_path(base::FilePath(kAccelerometerIioBasePath
).Append(
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
]);
196 if (!ReadFileToInt(iio_path
.Append(accelerometer_scale_path
.c_str()),
198 configuration_
.has
[i
] = false;
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
]))) {
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
])
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.";
237 configuration_
.length
= kDataSize
* 3 * configuration_
.count
;
238 initialization_successful_
= true;
242 void AccelerometerFileReader::Read() {
244 base::SequencedWorkerPool::GetSequenceTokenForCurrentThread().IsValid());
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(
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
;
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";
288 update_
= new AccelerometerUpdate();
290 for (int i
= 0; i
< ACCELEROMETER_SOURCE_COUNT
; ++i
) {
291 if (!configuration_
.has
[i
])
294 int16
* values
= reinterpret_cast<int16
*>(reading
);
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
,
307 AccelerometerFileReader::ConfigurationData::ConfigurationData() : count(0) {
308 for (int i
= 0; i
< ACCELEROMETER_SOURCE_COUNT
; ++i
) {
310 for (int j
= 0; j
< 3; ++j
) {
317 AccelerometerFileReader::ConfigurationData::~ConfigurationData() {
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
330 sequenced_task_runner
->PostNonNestableTask(
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