1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "androidcontexthub.h" 18 19#include <errno.h> 20#include <fcntl.h> 21#include <poll.h> 22#include <time.h> 23#include <unistd.h> 24#include <sys/stat.h> 25 26#include <chrono> 27#include <cstdint> 28#include <cstdio> 29#include <cstring> 30#include <thread> 31#include <vector> 32 33#include "calibrationfile.h" 34#include "log.h" 35 36namespace android { 37 38constexpr char kSensorDeviceFile[] = "/dev/nanohub"; 39constexpr char kCommsDeviceFile[] = "/dev/nanohub_comms"; 40constexpr char kLockDirectory[] = "/data/vendor/sensor/nanohub_lock"; 41constexpr char kLockFile[] = "/data/vendor/sensor/nanohub_lock/lock"; 42 43constexpr mode_t kLockDirPermissions = (S_IRUSR | S_IWUSR | S_IXUSR); 44 45constexpr auto kLockDelay = std::chrono::milliseconds(100); 46 47constexpr int kDeviceFileCount = 2; 48constexpr int kPollNoTimeout = -1; 49 50static const std::vector<std::tuple<const char *, SensorType>> kCalibrationKeys = { 51 std::make_tuple("accel", SensorType::Accel), 52 std::make_tuple("gyro", SensorType::Gyro), 53 std::make_tuple("mag", SensorType::Magnetometer), 54 std::make_tuple("proximity", SensorType::Proximity), 55 std::make_tuple("barometer", SensorType::Barometer), 56 std::make_tuple("light", SensorType::AmbientLightSensor), 57}; 58 59static void AppendBytes(const void *data, size_t length, std::vector<uint8_t>& buffer) { 60 const uint8_t *bytes = (const uint8_t *) data; 61 for (size_t i = 0; i < length; i++) { 62 buffer.push_back(bytes[i]); 63 } 64} 65 66static bool CopyInt32Array(const char *key, 67 sp<JSONObject> json, std::vector<uint8_t>& bytes) { 68 sp<JSONArray> array; 69 if (json->getArray(key, &array)) { 70 for (size_t i = 0; i < array->size(); i++) { 71 int32_t val = 0; 72 array->getInt32(i, &val); 73 AppendBytes(&val, sizeof(uint32_t), bytes); 74 } 75 76 return true; 77 } 78 return false; 79} 80 81static bool CopyFloatArray(const char *key, 82 sp<JSONObject> json, std::vector<uint8_t>& bytes) { 83 sp<JSONArray> array; 84 if (json->getArray(key, &array)) { 85 for (size_t i = 0; i < array->size(); i++) { 86 float val = 0; 87 array->getFloat(i, &val); 88 AppendBytes(&val, sizeof(float), bytes); 89 } 90 91 return true; 92 } 93 return false; 94} 95 96static bool GetCalibrationBytes(const char *key, SensorType sensor_type, 97 std::vector<uint8_t>& bytes) { 98 bool success = true; 99 std::shared_ptr<CalibrationFile> cal_file = CalibrationFile::Instance(); 100 if (!cal_file) { 101 return false; 102 } 103 auto json = cal_file->GetJSONObject(); 104 105 switch (sensor_type) { 106 case SensorType::Accel: 107 case SensorType::Gyro: 108 success = CopyInt32Array(key, json, bytes); 109 break; 110 111 case SensorType::Magnetometer: 112 success = CopyFloatArray(key, json, bytes); 113 break; 114 115 case SensorType::AmbientLightSensor: 116 case SensorType::Barometer: { 117 float value = 0; 118 success = json->getFloat(key, &value); 119 if (success) { 120 AppendBytes(&value, sizeof(float), bytes); 121 } 122 break; 123 } 124 125 case SensorType::Proximity: { 126 // Proximity might be an int32 array with 4 values (CRGB) or a single 127 // int32 value - try both 128 success = CopyInt32Array(key, json, bytes); 129 if (!success) { 130 int32_t value = 0; 131 success = json->getInt32(key, &value); 132 if (success) { 133 AppendBytes(&value, sizeof(int32_t), bytes); 134 } 135 } 136 break; 137 } 138 139 default: 140 // If this log message gets printed, code needs to be added in this 141 // switch statement 142 LOGE("Missing sensor type to calibration data mapping sensor %d", 143 static_cast<int>(sensor_type)); 144 success = false; 145 } 146 147 return success; 148} 149 150AndroidContextHub::~AndroidContextHub() { 151 if (unlink(kLockFile) < 0) { 152 LOGE("Couldn't remove lock file: %s", strerror(errno)); 153 } 154 if (sensor_fd_ >= 0) { 155 DisableActiveSensors(); 156 (void) close(sensor_fd_); 157 } 158 if (comms_fd_ >= 0) { 159 (void) close(comms_fd_); 160 } 161} 162 163void AndroidContextHub::TerminateHandler() { 164 (void) unlink(kLockFile); 165} 166 167bool AndroidContextHub::Initialize() { 168 // Acquire a lock on nanohub, so the HAL read threads won't take our events. 169 // We need to delay after creating the file to have good confidence that 170 // the HALs noticed the lock file creation. 171 if (access(kLockDirectory, F_OK) < 0) { 172 if (mkdir(kLockDirectory, kLockDirPermissions) < 0 && errno != EEXIST) { 173 LOGE("Couldn't create lock directory: %s", strerror(errno)); 174 } 175 } 176 int lock_fd = open(kLockFile, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 177 if (lock_fd < 0) { 178 LOGE("Couldn't create lock file: %s", strerror(errno)); 179 if (errno != EEXIST) { 180 return false; 181 } 182 } else { 183 close(lock_fd); 184 std::this_thread::sleep_for(kLockDelay); 185 LOGD("Lock sleep complete"); 186 } 187 188 // Sensor device file is used for sensor requests, e.g. configure, etc., and 189 // returns sensor events 190 sensor_fd_ = open(kSensorDeviceFile, O_RDWR); 191 if (sensor_fd_ < 0) { 192 LOGE("Couldn't open device file: %s", strerror(errno)); 193 return false; 194 } 195 196 // The comms device file is used for more generic communication with 197 // nanoapps. Calibration results are returned through this channel. 198 comms_fd_ = open(kCommsDeviceFile, O_RDONLY); 199 if (comms_fd_ < 0) { 200 // TODO(bduddie): Currently informational only, as the kernel change 201 // that adds this device file is not available/propagated yet. 202 // Eventually this should be an error. 203 LOGI("Couldn't open comms device file: %s", strerror(errno)); 204 } 205 206 return true; 207} 208 209void AndroidContextHub::SetLoggingEnabled(bool logging_enabled) { 210 if (logging_enabled) { 211 LOGE("Logging is not supported on this platform"); 212 } 213} 214 215ContextHub::TransportResult AndroidContextHub::WriteEvent( 216 const std::vector<uint8_t>& message) { 217 ContextHub::TransportResult result; 218 219 LOGD("Writing %zu bytes", message.size()); 220 LOGD_BUF(message.data(), message.size()); 221 int ret = write(sensor_fd_, message.data(), message.size()); 222 if (ret == -1) { 223 LOGE("Couldn't write %zu bytes to device file: %s", message.size(), 224 strerror(errno)); 225 result = TransportResult::GeneralFailure; 226 } else if (ret != (int) message.size()) { 227 LOGW("Write returned %d, expected %zu", ret, message.size()); 228 result = TransportResult::GeneralFailure; 229 } else { 230 LOGD("Successfully sent event"); 231 result = TransportResult::Success; 232 } 233 234 return result; 235} 236 237ContextHub::TransportResult AndroidContextHub::ReadEvent( 238 std::vector<uint8_t>& message, int timeout_ms) { 239 ContextHub::TransportResult result = TransportResult::GeneralFailure; 240 241 struct pollfd pollfds[kDeviceFileCount]; 242 int fd_count = ResetPollFds(pollfds, kDeviceFileCount); 243 244 int timeout = timeout_ms > 0 ? timeout_ms : kPollNoTimeout; 245 int ret = poll(pollfds, fd_count, timeout); 246 if (ret < 0) { 247 LOGE("Polling failed: %s", strerror(errno)); 248 if (errno == EINTR) { 249 result = TransportResult::Canceled; 250 } 251 } else if (ret == 0) { 252 LOGD("Poll timed out"); 253 result = TransportResult::Timeout; 254 } else { 255 int read_fd = -1; 256 for (int i = 0; i < kDeviceFileCount; i++) { 257 if (pollfds[i].revents & POLLIN) { 258 read_fd = pollfds[i].fd; 259 break; 260 } 261 } 262 263 if (read_fd == sensor_fd_) { 264 LOGD("Data ready on sensors device file"); 265 } else if (read_fd == comms_fd_) { 266 LOGD("Data ready on comms device file"); 267 } 268 269 if (read_fd >= 0) { 270 result = ReadEventFromFd(read_fd, message); 271 } else { 272 LOGE("Poll returned but none of expected files are ready"); 273 } 274 } 275 276 return result; 277} 278 279bool AndroidContextHub::FlashSensorHub(const std::vector<uint8_t>& bytes) { 280 (void)bytes; 281 LOGE("Flashing is not supported on this platform"); 282 return false; 283} 284 285bool AndroidContextHub::LoadCalibration() { 286 std::vector<uint8_t> cal_data; 287 bool success = true; 288 289 for (size_t i = 0; success && i < kCalibrationKeys.size(); i++) { 290 std::string key; 291 SensorType sensor_type; 292 293 std::tie(key, sensor_type) = kCalibrationKeys[i]; 294 if (GetCalibrationBytes(key.c_str(), sensor_type, cal_data)) { 295 success = SendCalibrationData(sensor_type, cal_data); 296 } 297 298 cal_data.clear(); 299 } 300 301 return success; 302} 303 304bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t data) { 305 LOGI("Setting calibration for sensor %d (%s) to %d", 306 static_cast<int>(sensor_type), 307 ContextHub::SensorTypeToAbbrevName(sensor_type).c_str(), data); 308 auto cal_file = CalibrationFile::Instance(); 309 const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type); 310 if (cal_file && key) { 311 return cal_file->SetSingleAxis(key, data); 312 } 313 return false; 314} 315 316bool AndroidContextHub::SetCalibration(SensorType sensor_type, float data) { 317 LOGI("Setting calibration for sensor %d (%s) to %f", 318 static_cast<int>(sensor_type), 319 ContextHub::SensorTypeToAbbrevName(sensor_type).c_str(), data); 320 auto cal_file = CalibrationFile::Instance(); 321 const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type); 322 if (cal_file && key) { 323 return cal_file->SetSingleAxis(key, data); 324 } 325 return false; 326} 327 328bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t x, 329 int32_t y, int32_t z) { 330 LOGI("Setting calibration for %d to %d %d %d", static_cast<int>(sensor_type), 331 x, y, z); 332 auto cal_file = CalibrationFile::Instance(); 333 const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type); 334 if (cal_file && key) { 335 return cal_file->SetTripleAxis(key, x, y, z); 336 } 337 return false; 338} 339 340bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t x, 341 int32_t y, int32_t z, int32_t w) { 342 LOGI("Setting calibration for %d to %d %d %d %d", static_cast<int>(sensor_type), 343 x, y, z, w); 344 auto cal_file = CalibrationFile::Instance(); 345 const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type); 346 if (cal_file && key) { 347 return cal_file->SetFourAxis(key, x, y, z, w); 348 } 349 return false; 350} 351 352bool AndroidContextHub::SaveCalibration() { 353 LOGI("Saving calibration data"); 354 auto cal_file = CalibrationFile::Instance(); 355 if (cal_file) { 356 return cal_file->Save(); 357 } 358 return false; 359} 360 361ContextHub::TransportResult AndroidContextHub::ReadEventFromFd( 362 int fd, std::vector<uint8_t>& message) { 363 ContextHub::TransportResult result = TransportResult::GeneralFailure; 364 365 // Set the size to the maximum, so when we resize later, it's always a 366 // shrink (otherwise it will end up clearing the bytes) 367 message.resize(message.capacity()); 368 369 LOGD("Calling into read()"); 370 int ret = read(fd, message.data(), message.capacity()); 371 if (ret < 0) { 372 LOGE("Couldn't read from device file: %s", strerror(errno)); 373 if (errno == EINTR) { 374 result = TransportResult::Canceled; 375 } 376 } else if (ret == 0) { 377 // We might need to handle this specially, if the driver implements this 378 // to mean something specific 379 LOGE("Read unexpectedly returned 0 bytes"); 380 } else { 381 message.resize(ret); 382 LOGD_VEC(message); 383 result = TransportResult::Success; 384 } 385 386 return result; 387} 388 389int AndroidContextHub::ResetPollFds(struct pollfd *pfds, size_t count) { 390 memset(pfds, 0, sizeof(struct pollfd) * count); 391 pfds[0].fd = sensor_fd_; 392 pfds[0].events = POLLIN; 393 394 int nfds = 1; 395 if (count > 1 && comms_fd_ >= 0) { 396 pfds[1].fd = comms_fd_; 397 pfds[1].events = POLLIN; 398 nfds++; 399 } 400 return nfds; 401} 402 403const char *AndroidContextHub::SensorTypeToCalibrationKey(SensorType sensor_type) { 404 for (size_t i = 0; i < kCalibrationKeys.size(); i++) { 405 const char *key; 406 SensorType sensor_type_for_key; 407 408 std::tie(key, sensor_type_for_key) = kCalibrationKeys[i]; 409 if (sensor_type == sensor_type_for_key) { 410 return key; 411 } 412 } 413 414 LOGE("No calibration key mapping for sensor type %d", 415 static_cast<int>(sensor_type)); 416 return nullptr; 417} 418 419} // namespace android 420