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 <chre.h> 18 #include <cinttypes> 19 20 #include "chre/util/macros.h" 21 #include "chre/util/nanoapp/log.h" 22 #include "chre/util/nanoapp/sensor.h" 23 #include "chre/util/time.h" 24 25 #define LOG_TAG "[SensorWorld]" 26 27 #ifdef CHRE_NANOAPP_INTERNAL 28 namespace chre { 29 namespace { 30 #endif // CHRE_NANOAPP_INTERNAL 31 32 using chre::Milliseconds; 33 using chre::Seconds; 34 using chre::getSensorNameForEventType; 35 using chre::kOneMillisecondInNanoseconds; 36 37 namespace { 38 39 //! Enable BreakIt test mode. 40 // In BreakIt test mode, a timer will be set periodically to randomly 41 // enable/disable each sensor. 42 constexpr bool kBreakIt = false; 43 constexpr Milliseconds kBreakItPeriod = Milliseconds(2000); 44 45 //! Whether to enable sensor event logging or not. 46 constexpr bool kEnableSensorEventLogging = true; 47 48 //! Enable/disable all sensors by default. 49 // This allows disabling all sensens by default and enabling only targeted 50 // sensors for testing by locally overriding 'enable' field in SensorState. 51 // Note that enabling BreakIt test disables all sensors at init by default. 52 constexpr bool kEnableDefault = !kBreakIt; 53 54 struct SensorState { 55 const uint8_t type; 56 uint32_t handle; 57 bool isInitialized; 58 bool enable; 59 uint64_t interval; // nsec 60 uint64_t latency; // nsec 61 chreSensorInfo info; 62 }; 63 64 SensorState sensors[] = { 65 { .type = CHRE_SENSOR_TYPE_ACCELEROMETER, 66 .handle = 0, 67 .isInitialized = false, 68 .enable = kEnableDefault, 69 .interval = Milliseconds(80).toRawNanoseconds(), 70 .latency = Seconds(4).toRawNanoseconds(), 71 .info = {}, 72 }, 73 { .type = CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT, 74 .handle = 0, 75 .isInitialized = false, 76 .enable = false, // InstantMotion is triggered by Prox 77 .interval = CHRE_SENSOR_INTERVAL_DEFAULT, 78 .latency = CHRE_SENSOR_LATENCY_DEFAULT, 79 .info = {}, 80 }, 81 { .type = CHRE_SENSOR_TYPE_STATIONARY_DETECT, 82 .handle = 0, 83 .isInitialized = false, 84 .enable = false, // StationaryDetect is triggered by Prox 85 .interval = CHRE_SENSOR_INTERVAL_DEFAULT, 86 .latency = CHRE_SENSOR_LATENCY_DEFAULT, 87 .info = {}, 88 }, 89 { .type = CHRE_SENSOR_TYPE_GYROSCOPE, 90 .handle = 0, 91 .isInitialized = false, 92 .enable = kEnableDefault, 93 .interval = Milliseconds(80).toRawNanoseconds(), 94 .latency = Seconds(4).toRawNanoseconds(), 95 .info = {}, 96 }, 97 { .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD, 98 .handle = 0, 99 .isInitialized = false, 100 .enable = kEnableDefault, 101 .interval = Milliseconds(80).toRawNanoseconds(), 102 .latency = Seconds(4).toRawNanoseconds(), 103 .info = {}, 104 }, 105 { .type = CHRE_SENSOR_TYPE_PRESSURE, 106 .handle = 0, 107 .isInitialized = false, 108 .enable = kEnableDefault, 109 .interval = Milliseconds(200).toRawNanoseconds(), 110 .latency = Seconds(4).toRawNanoseconds(), 111 .info = {}, 112 }, 113 { .type = CHRE_SENSOR_TYPE_LIGHT, 114 .handle = 0, 115 .isInitialized = false, 116 .enable = kEnableDefault, 117 .interval = Milliseconds(200).toRawNanoseconds(), 118 .latency = 0, 119 .info = {}, 120 }, 121 { .type = CHRE_SENSOR_TYPE_PROXIMITY, 122 .handle = 0, 123 .isInitialized = false, 124 .enable = kEnableDefault, 125 .interval = Milliseconds(200).toRawNanoseconds(), 126 .latency = 0, 127 .info = {}, 128 }, 129 { .type = CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE, 130 .handle = 0, 131 .isInitialized = false, 132 .enable = kEnableDefault, 133 .interval = Seconds(2).toRawNanoseconds(), 134 .latency = 0, 135 .info = {}, 136 }, 137 { .type = CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE, 138 .handle = 0, 139 .isInitialized = false, 140 .enable = kEnableDefault, 141 .interval = Seconds(2).toRawNanoseconds(), 142 .latency = 0, 143 .info = {}, 144 }, 145 { .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE, 146 .handle = 0, 147 .isInitialized = false, 148 .enable = kEnableDefault, 149 .interval = Seconds(2).toRawNanoseconds(), 150 .latency = 0, 151 .info = {}, 152 }, 153 { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER, 154 .handle = 0, 155 .isInitialized = false, 156 .enable = kEnableDefault, 157 .interval = Milliseconds(80).toRawNanoseconds(), 158 .latency = Seconds(4).toRawNanoseconds(), 159 .info = {}, 160 }, 161 { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE, 162 .handle = 0, 163 .isInitialized = false, 164 .enable = kEnableDefault, 165 .interval = Milliseconds(80).toRawNanoseconds(), 166 .latency = Seconds(4).toRawNanoseconds(), 167 .info = {}, 168 }, 169 { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD, 170 .handle = 0, 171 .isInitialized = false, 172 .enable = kEnableDefault, 173 .interval = Milliseconds(80).toRawNanoseconds(), 174 .latency = Seconds(4).toRawNanoseconds(), 175 .info = {}, 176 }, 177 }; 178 179 uint32_t gBreakItTimerHandle; 180 181 // Conditional logging macro 182 #define CLOGI(fmt, ...) do { \ 183 if (kEnableSensorEventLogging) { \ 184 LOGI(fmt, ##__VA_ARGS__); \ 185 } \ 186 } while (0); 187 188 // Helpers for testing InstantMotion and StationaryDetect 189 enum class MotionMode { 190 Instant, 191 Stationary, 192 }; 193 194 // Storage to help access InstantMotion and StationaryDetect sensor handle and 195 // info 196 size_t motionSensorIndices[2]; 197 MotionMode motionMode = MotionMode::Instant; 198 199 size_t getMotionSensorIndex() { 200 motionMode = (motionMode == MotionMode::Instant) ? 201 MotionMode::Stationary : MotionMode::Instant; 202 return motionSensorIndices[static_cast<size_t>(motionMode)]; 203 } 204 205 //! Used to loop through all sensors to query sensor sampling status. 206 size_t statusIndex = 0; 207 208 // Obtains 16-bit psuedo-random numbers. 209 uint16_t getNextLfsrState() { 210 // 15-bit LFSR with feedback polynomial x^15 + x^14 + 1 gives us a 211 // pseudo-random sequence over all 32767 possible values 212 static uint16_t lfsr = 0x1337; 213 uint16_t nextBit = ((lfsr << 14) ^ (lfsr << 13)) & 0x4000; 214 lfsr = nextBit | (lfsr >> 1); 215 216 return lfsr; 217 } 218 219 void handleTimerEvent(const void *eventData) { 220 for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { 221 SensorState& sensor = sensors[i]; 222 223 bool enable = getNextLfsrState() & 0x1; 224 if (sensor.isInitialized && sensor.enable != enable) { 225 sensor.enable = enable; 226 227 bool status; 228 if (!enable) { 229 status = chreSensorConfigureModeOnly( 230 sensor.handle, CHRE_SENSOR_CONFIGURE_MODE_DONE); 231 } else { 232 enum chreSensorConfigureMode mode = sensor.info.isOneShot 233 ? CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT 234 : CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS; 235 status = chreSensorConfigure( 236 sensor.handle, mode, sensor.interval, sensor.latency); 237 } 238 239 LOGI("Configure [enable %d, status %d]: %s", 240 enable, status, getSensorTypeName(sensor.type)); 241 } 242 } 243 244 gBreakItTimerHandle = chreTimerSet(kBreakItPeriod.toRawNanoseconds(), 245 nullptr /* data */, true /* oneShot */); 246 } 247 248 } // namespace 249 250 bool nanoappStart() { 251 LOGI("App started on platform ID %" PRIx64, chreGetPlatformId()); 252 253 for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { 254 SensorState& sensor = sensors[i]; 255 sensor.isInitialized = chreSensorFindDefault(sensor.type, &sensor.handle); 256 LOGI("Sensor %zu initialized: %s with handle %" PRIu32, 257 i, sensor.isInitialized ? "true" : "false", sensor.handle); 258 259 if (sensor.type == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT) { 260 motionSensorIndices[static_cast<size_t>(MotionMode::Instant)] = i; 261 } else if (sensor.type == CHRE_SENSOR_TYPE_STATIONARY_DETECT) { 262 motionSensorIndices[static_cast<size_t>(MotionMode::Stationary)] = i; 263 } 264 265 if (sensor.isInitialized) { 266 // Get sensor info 267 chreSensorInfo& info = sensor.info; 268 bool infoStatus = chreGetSensorInfo(sensor.handle, &info); 269 if (infoStatus) { 270 LOGI("SensorInfo: %s, Type=%" PRIu8 " OnChange=%d" 271 " OneShot=%d minInterval=%" PRIu64 "nsec", 272 info.sensorName, info.sensorType, info.isOnChange, 273 info.isOneShot, info.minInterval); 274 } else { 275 LOGE("chreGetSensorInfo failed"); 276 } 277 278 // Subscribe to sensors 279 if (sensor.enable) { 280 float odrHz = 1e9f / sensor.interval; 281 float latencySec = sensor.latency / 1e9f; 282 bool status = chreSensorConfigure(sensor.handle, 283 CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS, sensor.interval, 284 sensor.latency); 285 LOGI("Requested data: odr %f Hz, latency %f sec, %s", 286 odrHz, latencySec, status ? "success" : "failure"); 287 } 288 } 289 } 290 291 // Set timer for BreakIt test. 292 if (kBreakIt) { 293 gBreakItTimerHandle = chreTimerSet(kBreakItPeriod.toRawNanoseconds(), 294 nullptr /* data */, true /* oneShot */); 295 } 296 297 return true; 298 } 299 300 void nanoappHandleEvent(uint32_t senderInstanceId, 301 uint16_t eventType, 302 const void *eventData) { 303 uint64_t chreTime = chreGetTime(); 304 uint64_t sampleTime; 305 switch (eventType) { 306 case CHRE_EVENT_SENSOR_ACCELEROMETER_DATA: 307 case CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA: 308 case CHRE_EVENT_SENSOR_GYROSCOPE_DATA: 309 case CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA: 310 case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA: 311 case CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA: { 312 const auto *ev = static_cast<const chreSensorThreeAxisData *>(eventData); 313 const auto header = ev->header; 314 const auto *data = ev->readings; 315 sampleTime = header.baseTimestamp; 316 317 float x = 0, y = 0, z = 0; 318 for (size_t i = 0; i < header.readingCount; i++) { 319 x += data[i].v[0]; 320 y += data[i].v[1]; 321 z += data[i].v[2]; 322 sampleTime += data[i].timestampDelta; 323 } 324 x /= header.readingCount; 325 y /= header.readingCount; 326 z /= header.readingCount; 327 328 CLOGI("%s, %d samples: %f %f %f, t=%" PRIu64 " ms", 329 getSensorNameForEventType(eventType), header.readingCount, x, y, z, 330 header.baseTimestamp / kOneMillisecondInNanoseconds); 331 332 if (eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA) { 333 CLOGI("UncalGyro time: first %" PRIu64 " last %" PRIu64 " chre %" PRIu64 334 " delta [%" PRId64 ", %" PRId64 "]ms", 335 header.baseTimestamp, sampleTime, chreTime, 336 static_cast<int64_t>(header.baseTimestamp - chreTime) 337 / static_cast<int64_t>(kOneMillisecondInNanoseconds), 338 static_cast<int64_t>(sampleTime - chreTime) 339 / static_cast<int64_t>(kOneMillisecondInNanoseconds)); 340 } 341 break; 342 } 343 344 case CHRE_EVENT_SENSOR_PRESSURE_DATA: 345 case CHRE_EVENT_SENSOR_LIGHT_DATA: 346 case CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA: 347 case CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA: 348 case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_TEMPERATURE_DATA: { 349 const auto *ev = static_cast<const chreSensorFloatData *>(eventData); 350 const auto header = ev->header; 351 352 float v = 0; 353 for (size_t i = 0; i < header.readingCount; i++) { 354 v += ev->readings[i].value; 355 } 356 v /= header.readingCount; 357 358 CLOGI("%s, %d samples: %f, t=%" PRIu64 " ms", 359 getSensorNameForEventType(eventType), header.readingCount, v, 360 header.baseTimestamp / kOneMillisecondInNanoseconds); 361 break; 362 } 363 364 case CHRE_EVENT_SENSOR_PROXIMITY_DATA: { 365 const auto *ev = static_cast<const chreSensorByteData *>(eventData); 366 const auto header = ev->header; 367 const auto reading = ev->readings[0]; 368 sampleTime = header.baseTimestamp; 369 370 CLOGI("%s, %d samples: isNear %d, invalid %d", 371 getSensorNameForEventType(eventType), header.readingCount, 372 reading.isNear, reading.invalid); 373 374 CLOGI("Prox time: sample %" PRIu64 " chre %" PRIu64 " delta %" PRId64 375 "ms", header.baseTimestamp, chreTime, 376 static_cast<int64_t>(sampleTime - chreTime) / 1000000); 377 378 // Enable InstantMotion and StationaryDetect alternatively on near->far. 379 if (reading.isNear == 0 && !kBreakIt) { 380 size_t motionSensorIndex = getMotionSensorIndex(); 381 bool status = chreSensorConfigure(sensors[motionSensorIndex].handle, 382 CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT, 383 CHRE_SENSOR_INTERVAL_DEFAULT, 384 CHRE_SENSOR_LATENCY_DEFAULT); 385 LOGI("Requested %s: %s", sensors[motionSensorIndex].info.sensorName, 386 status ? "success" : "failure"); 387 } 388 389 // Exercise chreGetSensorSamplingStatus on one sensor on near->far. 390 if (sensors[statusIndex].isInitialized && reading.isNear == 0) { 391 struct chreSensorSamplingStatus status; 392 bool success = chreGetSensorSamplingStatus(sensors[statusIndex].handle, 393 &status); 394 LOGI("%s success %d: enabled %d interval %" PRIu64 " latency %" PRIu64, 395 sensors[statusIndex].info.sensorName, success, status.enabled, 396 status.interval, status.latency); 397 } 398 statusIndex = (statusIndex + 1) % ARRAY_SIZE(sensors); 399 break; 400 } 401 402 case CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA: 403 case CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA: { 404 const auto *ev = static_cast<const chreSensorOccurrenceData *>(eventData); 405 const auto header = ev->header; 406 407 CLOGI("%s, %d samples", 408 getSensorNameForEventType(eventType), header.readingCount); 409 break; 410 } 411 412 case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: { 413 const auto *ev = static_cast<const chreSensorSamplingStatusEvent *>( 414 eventData); 415 416 CLOGI("Sampling Change: handle %" PRIu32 ", status: interval %" PRIu64 417 " latency %" PRIu64 " enabled %d", 418 ev->sensorHandle, ev->status.interval, ev->status.latency, 419 ev->status.enabled); 420 break; 421 } 422 423 424 case CHRE_EVENT_TIMER: 425 if (!kBreakIt) { 426 LOGE("Timer event received with gBreakIt is disabled"); 427 } else { 428 handleTimerEvent(eventData); 429 } 430 break; 431 432 default: 433 LOGW("Unhandled event %d", eventType); 434 break; 435 } 436 } 437 438 void nanoappEnd() { 439 LOGI("Stopped"); 440 } 441 442 #ifdef CHRE_NANOAPP_INTERNAL 443 } // anonymous namespace 444 } // namespace chre 445 446 #include "chre/util/nanoapp/app_id.h" 447 #include "chre/platform/static_nanoapp_init.h" 448 449 CHRE_STATIC_NANOAPP_INIT(SensorWorld, chre::kSensorWorldAppId, 0); 450 #endif // CHRE_NANOAPP_INTERNAL 451