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