Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: chromeos/accelerometer/accelerometer_reader.cc

Issue 200643005: Read and expose accelerometer values from cros-ec-accel trigger. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments, update to use udev symlink to determine device name. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/safe_sprintf.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/task_runner_util.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "content/public/browser/browser_thread.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 containing the scales of the accelerometers.
Daniel Erat 2014/03/26 22:26:14 nit: mention that these are files within kAccelero
flackr 2014/03/27 15:21:07 Done.
31 const base::FilePath::CharType kAccelerometerBaseScalePath[] =
32 FILE_PATH_LITERAL("in_accel_base_scale");
33 const base::FilePath::CharType kAccelerometerLidScalePath[] =
34 FILE_PATH_LITERAL("in_accel_lid_scale");
35
36 // The filename giving the path to read the scan index of each accelerometer
37 // axis.
38 const char kAccelerometerScanIndexPath[] =
39 "scan_elements/in_accel_%s_%s_index";
40
41 // The maximum length string needed to store the accelerometer scan index path.
42 // i.e. kAccelerometerScanIndexPath with the longest of kAccelerometerNames and
43 // kAccelerometerAxes filled in. This cannot be computed as it then fails to
44 // find a template match to SafeSPrintf in AccelerometerReader::Initialize for
45 // the array sized to the computed value.
46 const size_t kMaxAccelerometerScanIndexPathLength = 37;
47
48 // The names of the accelerometers and axes in the order we want to read them.
49 const char kAccelerometerNames[][5] = {"base", "lid"};
50 const char kAccelerometerAxes[][2] = {"x", "y", "z"};
51 const size_t kTriggerDataLength =
52 2 * arraysize(kAccelerometerNames) * arraysize(kAccelerometerAxes);
53
54 // The length required to read uint values from configuration files.
55 const unsigned int kMaxAsciiUintLength = 21;
Daniel Erat 2014/03/26 22:26:14 nit: s/unsigned int/size_t/
flackr 2014/03/27 15:21:07 Done.
56
57 // The time to wait between reading the accelerometer.
58 const unsigned int kDelayBetweenReadsMilliseconds = 100;
Daniel Erat 2014/03/26 22:26:14 nit: just use int here, maybe also s/Milliseconds/
flackr 2014/03/27 15:21:07 Done.
59
60 // Reads |path| to the unsigned int pointed to by |value|. Returns true on
61 // success or false on failure.
62 bool ReadFileToUint(const base::FilePath& path, unsigned int* value) {
63 std::string s;
64 DCHECK(value);
65 if (!base::ReadFileToString(path,
66 &s, kMaxAsciiUintLength)) {
Daniel Erat 2014/03/26 22:26:14 nit: can you unwrap this line?
flackr 2014/03/27 15:21:07 Done.
67 LOG(ERROR) << "Failed to read " << path.value();
68 return false;
69 }
70 base::TrimString(s, "\r\n", &s);
Daniel Erat 2014/03/26 22:26:14 nit: base::TrimWhitespace(s, base::TRIM_ALL, &s)?
flackr 2014/03/27 15:21:07 Done.
71 if (!base::StringToUint(s, value)) {
72 LOG(ERROR) << "Failed to parse \"" << s << "\" from " << path.value();
73 return false;
74 }
75 return true;
76 }
77
78 } // namespace
79
80 using content::BrowserThread;
81
82 AccelerometerReader::AccelerometerReader(AccelerometerDelegate* delegate)
83 : delegate_(delegate),
84 has_accelerometer_(false),
85 weak_factory_(this) {
86 // Asynchronously detect and initialize the accelerometer to avoid delaying
87 // startup.
88 base::PostTaskAndReplyWithResult(
89 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
flackr 2014/03/26 19:06:48 Is there a better way to post a non-blocking task
Daniel Erat 2014/03/26 22:26:14 i think that the blocking pool is the right place
90 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
Daniel Erat 2014/03/26 22:26:14 if you don't need the SKIP_ON_SHUTDOWN semantics (
flackr 2014/03/27 15:21:07 Done.
91 FROM_HERE,
92 base::Bind(&AccelerometerReader::Initialize,
93 base::Unretained(this)),
Daniel Erat 2014/03/26 22:26:14 pass weak_ptrs instead to make sure that these tas
flackr 2014/03/27 15:21:07 Had to avoid return values because weak_ptrs_can_o
Daniel Erat 2014/03/27 15:37:51 ah, that's unfortunate.
94 base::Bind(&AccelerometerReader::OnInitialized,
95 base::Unretained(this)));
96 }
97
98 AccelerometerReader::~AccelerometerReader() {
99 }
100
101 bool AccelerometerReader::Initialize() {
Daniel Erat 2014/03/26 22:26:14 nit: DCHECK(BrowserThread::GetBlockingPool()->Runs
flackr 2014/03/27 15:21:07 Done.
102 // Check for accelerometer symlink which will be created by the udev rules
103 // file on detecting the device.
104 base::FilePath device;
105 if (!base::ReadSymbolicLink(base::FilePath(kAccelerometerDevicePath),
106 &device)) {
Daniel Erat 2014/03/26 22:26:14 just to check: this is expected for devices that d
flackr 2014/03/27 15:21:07 Yes.
107 return false;
108 }
109
110 if (!base::PathExists(base::FilePath(kAccelerometerTriggerPath))) {
111 LOG(ERROR) << "Accelerometer trigger does not exist.";
Daniel Erat 2014/03/26 22:26:14 nit: include kAccelerometerTriggerPath in the erro
flackr 2014/03/27 15:21:07 Done.
112 return false;
113 }
114
115 base::FilePath iio_path(base::FilePath(kAccelerometerIioBasePath).Append(
116 device));
117 // Read accelerometer scales
118 if (!ReadFileToUint(iio_path.Append(kAccelerometerBaseScalePath),
119 &accelerometer_base_scale_)) {
120 return false;
Daniel Erat 2014/03/26 22:26:14 nit: log an error and include kAccelerometerBaseSc
flackr 2014/03/27 15:21:07 For here and following uses, errors are already lo
Daniel Erat 2014/03/27 15:37:51 sure, sounds fine.
121 }
122 if (!ReadFileToUint(iio_path.Append(kAccelerometerLidScalePath),
123 &accelerometer_lid_scale_)) {
124 return false;
Daniel Erat 2014/03/26 22:26:14 nit: log an error and include kAccelerometerLidSca
flackr 2014/03/27 15:21:07 See comment above.
125 }
126
127 // Read indices of each accelerometer axis from each accelerometer from
128 // /sys/bus/iio/devices/iio:deviceX/scan_elements/in_accel_{x,y,z}_%s_index
129 for (size_t i = 0; i < arraysize(kAccelerometerNames); ++i) {
130 for (size_t j = 0; j < arraysize(kAccelerometerAxes); ++j) {
131 char accelerometer_index_path[kMaxAccelerometerScanIndexPathLength];
132 unsigned int index = 0;
133 base::strings::SafeSPrintf(accelerometer_index_path,
Daniel Erat 2014/03/26 22:26:14 can you just use an std::string in conjunction wit
flackr 2014/03/27 15:21:07 Done.
134 kAccelerometerScanIndexPath, kAccelerometerAxes[j],
135 kAccelerometerNames[i]);
136 if (!ReadFileToUint(iio_path.Append(accelerometer_index_path),
137 &index)) {
138 return false;
Daniel Erat 2014/03/26 22:26:14 nit: log an error and include the path name in the
flackr 2014/03/27 15:21:07 See comment above.
139 }
140 accelerometer_index_.push_back(index);
Daniel Erat 2014/03/26 22:26:14 do bounds-checking here to ensure that a buggy/mal
flackr 2014/03/27 15:21:07 Done.
141 }
142 }
143 return true;
144 }
145
146 void AccelerometerReader::OnInitialized(bool success) {
Daniel Erat 2014/03/26 22:26:14 nit: DCHECK(BrowserThread::CurrentlyOn(BrowserThre
flackr 2014/03/27 15:21:07 Done.
147 has_accelerometer_ = success;
148 if (has_accelerometer_)
149 TriggerRead();
150 }
151
152 void AccelerometerReader::TriggerRead() {
Daniel Erat 2014/03/26 22:26:14 nit: DCHECK(BrowserThread::CurrentlyOn(BrowserThre
flackr 2014/03/27 15:21:07 Done.
153 base::PostTaskAndReplyWithResult(
154 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
155 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
156 FROM_HERE,
157 base::Bind(&AccelerometerReader::ReadAccelerometer,
158 base::Unretained(this)),
159 base::Bind(&AccelerometerReader::OnDataRead,
160 base::Unretained(this)));
Daniel Erat 2014/03/26 22:26:14 same comments here as above
flackr 2014/03/27 15:21:07 Done.
161 }
162
163 bool AccelerometerReader::ReadAccelerometer() {
Daniel Erat 2014/03/26 22:26:14 nit: DCHECK(BrowserThread::GetBlockingPool()->Runs
flackr 2014/03/27 15:21:07 Done.
164 // Initiate the trigger to read accelerometers simultaneously
165 int bytesWritten = base::WriteFile(
Daniel Erat 2014/03/26 22:26:14 s/bytesWritten/bytes_written/
flackr 2014/03/27 15:21:07 Done.
166 base::FilePath(kAccelerometerTriggerPath), "1\n", 2);
167 if (bytesWritten < 2) {
168 LOG(ERROR) << "Accelerometer trigger failure: " << bytesWritten;
Daniel Erat 2014/03/26 22:26:14 nit: PLOG(ERROR)
flackr 2014/03/27 15:21:07 Done.
169 return false;
170 }
171
172 // Read resulting sample from /dev/cros-ec-accel.
173 char data[kTriggerDataLength];
174 int bytesRead = base::ReadFile(base::FilePath(kAccelerometerDevicePath),
Daniel Erat 2014/03/26 22:26:14 s/bytesRead/bytes_read/
flackr 2014/03/27 15:21:07 Done.
175 data, kTriggerDataLength);
Daniel Erat 2014/03/26 22:26:14 just out of curiosity: have you timed this? how lo
flackr 2014/03/27 15:21:07 I haven't timed it yet, but I can do this. I belie
176 if (bytesRead < static_cast<int>(kTriggerDataLength)) {
177 LOG(ERROR) << "Read " << bytesRead << " bytes, expected "
Daniel Erat 2014/03/26 22:26:14 nit: s/bytes/byte(s)/
flackr 2014/03/27 15:21:07 Done.
178 << kTriggerDataLength << " bytes from accelerometer";
179 return false;
180 }
181
182 base_accelerometer_.set_x(*((int16*)data + accelerometer_index_[0]));
Daniel Erat 2014/03/26 22:26:14 nit: use reinterpret_cast<int16*> instead of c-sty
flackr 2014/03/27 15:21:07 Done.
183 base_accelerometer_.set_y(*((int16*)data + accelerometer_index_[1]));
184 base_accelerometer_.set_z(*((int16*)data + accelerometer_index_[2]));
185 base_accelerometer_.Scale(1.0f / accelerometer_base_scale_);
186
187 lid_accelerometer_.set_x(*((int16*)data + accelerometer_index_[3]));
188 lid_accelerometer_.set_y(*((int16*)data + accelerometer_index_[4]));
189 lid_accelerometer_.set_z(*((int16*)data + accelerometer_index_[5]));
190 lid_accelerometer_.Scale(1.0f / accelerometer_lid_scale_);
Daniel Erat 2014/03/26 22:26:14 i'm a bit concerned that a future change could add
flackr 2014/03/27 15:21:07 I added a comment to this effect (in the header),
191 return true;
192 }
193
194 void AccelerometerReader::OnDataRead(bool success) {
Daniel Erat 2014/03/26 22:26:14 nit: DCHECK(BrowserThread::CurrentlyOn(BrowserThre
flackr 2014/03/27 15:21:07 Done.
195 // If successful, notify the AccelerometerDelegate.
196 if (success)
197 delegate_->OnAccelerometerRead(base_accelerometer_, lid_accelerometer_);
198
199 // Trigger another read after the current sampling delay.
200 base::MessageLoop::current()->PostDelayedTask(
201 FROM_HERE,
202 base::Bind(&AccelerometerReader::TriggerRead,
203 weak_factory_.GetWeakPtr()),
204 base::TimeDelta::FromMilliseconds(kDelayBetweenReadsMilliseconds));
205 }
206
207 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698