OLD | NEW |
---|---|
(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 | |
OLD | NEW |