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/files/file_util.h" 9 #include "base/location.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/task_runner.h" 15 #include "base/task_runner_util.h" 16 #include "base/threading/sequenced_worker_pool.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 // File within the device in kAccelerometerIioBasePath containing the scale of 31 // the accelerometers. 32 const base::FilePath::CharType kScaleNameFormatString[] = "in_accel_%s_scale"; 33 34 // The filename giving the path to read the scan index of each accelerometer 35 // axis. 36 const char kAccelerometerScanIndexPath[] = 37 "scan_elements/in_accel_%s_%s_index"; 38 39 // The names of the accelerometers. Matches up with the enum AccelerometerSource 40 // in ui/accelerometer/accelerometer_types.h. 41 const char kAccelerometerNames[ui::ACCELEROMETER_SOURCE_COUNT][5] = { 42 "lid", "base"}; 43 44 // The axes on each accelerometer. 45 const char kAccelerometerAxes[][2] = {"y", "x", "z"}; 46 47 // The length required to read uint values from configuration files. 48 const size_t kMaxAsciiUintLength = 21; 49 50 // The size of individual values. 51 const size_t kDataSize = 2; 52 53 // The time to wait between reading the accelerometer. 54 const int kDelayBetweenReadsMs = 100; 55 56 // The mean acceleration due to gravity on Earth in m/s^2. 57 const float kMeanGravity = 9.80665f; 58 59 // Reads |path| to the unsigned int pointed to by |value|. Returns true on 60 // success or false on failure. 61 bool ReadFileToInt(const base::FilePath& path, int* value) { 62 std::string s; 63 DCHECK(value); 64 if (!base::ReadFileToString(path, &s, kMaxAsciiUintLength)) { 65 return false; 66 } 67 base::TrimWhitespaceASCII(s, base::TRIM_ALL, &s); 68 if (!base::StringToInt(s, value)) { 69 LOG(ERROR) << "Failed to parse \"" << s << "\" from " << path.value(); 70 return false; 71 } 72 return true; 73 } 74 75 bool DetectAndReadAccelerometerConfiguration( 76 scoped_refptr<AccelerometerReader::Configuration> configuration) { 77 // Check for accelerometer symlink which will be created by the udev rules 78 // file on detecting the device. 79 base::FilePath device; 80 if (!base::ReadSymbolicLink(base::FilePath(kAccelerometerDevicePath), 81 &device)) { 82 return false; 83 } 84 85 if (!base::PathExists(base::FilePath(kAccelerometerTriggerPath))) { 86 LOG(ERROR) << "Accelerometer trigger does not exist at" 87 << kAccelerometerTriggerPath; 88 return false; 89 } 90 91 base::FilePath iio_path(base::FilePath(kAccelerometerIioBasePath).Append( 92 device)); 93 // Read configuration of each accelerometer axis from each accelerometer from 94 // /sys/bus/iio/devices/iio:deviceX/. 95 for (size_t i = 0; i < arraysize(kAccelerometerNames); ++i) { 96 // Read scale of accelerometer. 97 std::string accelerometer_scale_path = base::StringPrintf( 98 kScaleNameFormatString, kAccelerometerNames[i]); 99 int scale_divisor; 100 if (!ReadFileToInt(iio_path.Append(accelerometer_scale_path.c_str()), 101 &scale_divisor)) { 102 configuration->data.has[i] = false; 103 continue; 104 } 105 106 configuration->data.has[i] = true; 107 configuration->data.count++; 108 for (size_t j = 0; j < arraysize(kAccelerometerAxes); ++j) { 109 configuration->data.scale[i][j] = kMeanGravity / scale_divisor; 110 std::string accelerometer_index_path = base::StringPrintf( 111 kAccelerometerScanIndexPath, kAccelerometerAxes[j], 112 kAccelerometerNames[i]); 113 if (!ReadFileToInt(iio_path.Append(accelerometer_index_path.c_str()), 114 &(configuration->data.index[i][j]))) { 115 return false; 116 } 117 } 118 } 119 120 // Adjust the directions of accelerometers to match the AccelerometerUpdate 121 // type specified in ui/accelerometer/accelerometer_types.h. 122 configuration->data.scale[ui::ACCELEROMETER_SOURCE_SCREEN][0] *= -1.0f; 123 for (int i = 0; i < 3; ++i) { 124 configuration->data.scale[ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD][i] *= 125 -1.0f; 126 } 127 128 // Verify indices are within bounds. 129 for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) { 130 if (!configuration->data.has[i]) 131 continue; 132 for (int j = 0; j < 3; ++j) { 133 if (configuration->data.index[i][j] < 0 || 134 configuration->data.index[i][j] >= 135 3 * static_cast<int>(configuration->data.count)) { 136 LOG(ERROR) << "Field index for " << kAccelerometerNames[i] << " " 137 << kAccelerometerAxes[j] << " axis out of bounds."; 138 return false; 139 } 140 } 141 } 142 configuration->data.length = kDataSize * 3 * configuration->data.count; 143 return true; 144 } 145 146 bool ReadAccelerometer( 147 scoped_refptr<AccelerometerReader::Reading> reading, 148 size_t length) { 149 // Initiate the trigger to read accelerometers simultaneously 150 int bytes_written = base::WriteFile( 151 base::FilePath(kAccelerometerTriggerPath), "1\n", 2); 152 if (bytes_written < 2) { 153 PLOG(ERROR) << "Accelerometer trigger failure: " << bytes_written; 154 return false; 155 } 156 157 // Read resulting sample from /dev/cros-ec-accel. 158 int bytes_read = base::ReadFile(base::FilePath(kAccelerometerDevicePath), 159 reading->data, length); 160 if (bytes_read < static_cast<int>(length)) { 161 LOG(ERROR) << "Read " << bytes_read << " byte(s), expected " 162 << length << " bytes from accelerometer"; 163 return false; 164 } 165 return true; 166 } 167 168 } // namespace 169 170 AccelerometerReader::ConfigurationData::ConfigurationData() 171 : count(0) { 172 for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) { 173 has[i] = false; 174 for (int j = 0; j < 3; ++j) { 175 scale[i][j] = 0; 176 index[i][j] = -1; 177 } 178 } 179 } 180 181 AccelerometerReader::ConfigurationData::~ConfigurationData() { 182 } 183 184 AccelerometerReader::AccelerometerReader( 185 scoped_refptr<base::TaskRunner> blocking_task_runner, 186 AccelerometerReader::Delegate* delegate) 187 : task_runner_(blocking_task_runner), 188 delegate_(delegate), 189 configuration_(new AccelerometerReader::Configuration()), 190 weak_factory_(this) { 191 DCHECK(task_runner_.get()); 192 DCHECK(delegate_); 193 // Asynchronously detect and initialize the accelerometer to avoid delaying 194 // startup. 195 base::PostTaskAndReplyWithResult(task_runner_.get(), FROM_HERE, 196 base::Bind(&DetectAndReadAccelerometerConfiguration, configuration_), 197 base::Bind(&AccelerometerReader::OnInitialized, 198 weak_factory_.GetWeakPtr(), configuration_)); 199 } 200 201 AccelerometerReader::~AccelerometerReader() { 202 } 203 204 void AccelerometerReader::OnInitialized( 205 scoped_refptr<AccelerometerReader::Configuration> configuration, 206 bool success) { 207 if (success) 208 TriggerRead(); 209 } 210 211 void AccelerometerReader::TriggerRead() { 212 DCHECK(!task_runner_->RunsTasksOnCurrentThread()); 213 214 scoped_refptr<AccelerometerReader::Reading> reading( 215 new AccelerometerReader::Reading()); 216 base::PostTaskAndReplyWithResult(task_runner_.get(), 217 FROM_HERE, 218 base::Bind(&ReadAccelerometer, reading, 219 configuration_->data.length), 220 base::Bind(&AccelerometerReader::OnDataRead, 221 weak_factory_.GetWeakPtr(), 222 reading)); 223 } 224 225 void AccelerometerReader::OnDataRead( 226 scoped_refptr<AccelerometerReader::Reading> reading, 227 bool success) { 228 DCHECK(!task_runner_->RunsTasksOnCurrentThread()); 229 230 if (success) { 231 for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) { 232 if (!configuration_->data.has[i]) 233 continue; 234 235 int16* values = reinterpret_cast<int16*>(reading->data); 236 update_.Set(static_cast<ui::AccelerometerSource>(i), 237 values[configuration_->data.index[i][0]] * 238 configuration_->data.scale[i][0], 239 values[configuration_->data.index[i][1]] * 240 configuration_->data.scale[i][1], 241 values[configuration_->data.index[i][2]] * 242 configuration_->data.scale[i][2]); 243 } 244 delegate_->HandleAccelerometerUpdate(update_); 245 } 246 247 // Trigger another read after the current sampling delay. 248 base::MessageLoop::current()->PostDelayedTask( 249 FROM_HERE, 250 base::Bind(&AccelerometerReader::TriggerRead, 251 weak_factory_.GetWeakPtr()), 252 base::TimeDelta::FromMilliseconds(kDelayBetweenReadsMs)); 253 } 254 255 } // namespace chromeos 256