Chromium Code Reviews| 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 |