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 <cinttypes>
18
19 #include "chre/util/macros.h"
20 #include "chre/util/nanoapp/log.h"
21 #include "chre/util/time.h"
22 #include "chre_api/chre.h"
23
24 #define LOG_TAG "[SensorWorld]"
25
26 #ifdef CHRE_NANOAPP_INTERNAL
27 namespace chre {
28 namespace {
29 #endif // CHRE_NANOAPP_INTERNAL
30
31 using chre::kOneMillisecondInNanoseconds;
32 using chre::Milliseconds;
33 using chre::Seconds;
34
35 namespace {
36
37 //! Enable BreakIt test mode.
38 // In BreakIt test mode, a timer will be set periodically to randomly
39 // enable/disable each sensor.
40 constexpr bool kBreakIt = false;
41 constexpr Milliseconds kBreakItPeriod = Milliseconds(2000);
42 uint32_t gBreakItTimerHandle;
43
44 //! Enable chreSensorFlushAsync test
45 // When enabled, SensorWorld will set a timer to invoke
46 // chreSensorFlushAsync(sensors[kFlushSensorIndex].handle)
47 // halfway through sensors[kFlushSensorIndex].latency
48 //
49 // If CHRE_EVENT_SENSOR_FLUSH_COMPLETE is not received before
50 // kFlushItTimeout expires, an error message will be logged.
51 constexpr bool kFlushIt = true;
52 constexpr uint32_t kFlushCookie = 0xdeadbeef;
53 constexpr uint32_t kFlushSensorIndex = 0; // CHRE_SENSOR_TYPE_ACCELEROMETER
54 uint32_t gFlushItTimerHandle;
55
56 constexpr Milliseconds kFlushItTimeout = Milliseconds(5000);
57 uint32_t gFlushItTimeoutTimerHandle;
58
59 //! Whether to enable sensor event logging or not.
60 constexpr bool kEnableSensorEventLogging = true;
61
62 //! Enable/disable all sensors by default.
63 // This allows disabling all sensens by default and enabling only targeted
64 // sensors for testing by locally overriding 'enable' field in SensorState.
65 // Note that enabling BreakIt test disables all sensors at init by default.
66 constexpr bool kEnableDefault = !kBreakIt;
67
68 struct SensorState {
69 const uint8_t type;
70 const uint8_t sensorIndex;
71 uint32_t handle;
72 bool isInitialized;
73 bool enable;
74 uint64_t interval; // nsec
75 uint64_t latency; // nsec
76 chreSensorInfo info;
77 };
78
79 SensorState sensors[] = {
80 {
81 .type = CHRE_SENSOR_TYPE_ACCELEROMETER,
82 .sensorIndex = 0,
83 .handle = 0,
84 .isInitialized = false,
85 .enable = kEnableDefault,
86 .interval = Milliseconds(80).toRawNanoseconds(),
87 .latency = Seconds(4).toRawNanoseconds(),
88 .info = {},
89 },
90 {
91 .type = CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT,
92 .sensorIndex = 0,
93 .handle = 0,
94 .isInitialized = false,
95 .enable = false, // InstantMotion is triggered by Prox
96 .interval = CHRE_SENSOR_INTERVAL_DEFAULT,
97 .latency = CHRE_SENSOR_LATENCY_DEFAULT,
98 .info = {},
99 },
100 {
101 .type = CHRE_SENSOR_TYPE_STATIONARY_DETECT,
102 .sensorIndex = 0,
103 .handle = 0,
104 .isInitialized = false,
105 .enable = false, // StationaryDetect is triggered by Prox
106 .interval = CHRE_SENSOR_INTERVAL_DEFAULT,
107 .latency = CHRE_SENSOR_LATENCY_DEFAULT,
108 .info = {},
109 },
110 {
111 .type = CHRE_SENSOR_TYPE_GYROSCOPE,
112 .sensorIndex = 0,
113 .handle = 0,
114 .isInitialized = false,
115 .enable = kEnableDefault,
116 .interval = Milliseconds(80).toRawNanoseconds(),
117 .latency = Seconds(4).toRawNanoseconds(),
118 .info = {},
119 },
120 {
121 .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD,
122 .sensorIndex = 0,
123 .handle = 0,
124 .isInitialized = false,
125 .enable = kEnableDefault,
126 .interval = Milliseconds(80).toRawNanoseconds(),
127 .latency = Seconds(4).toRawNanoseconds(),
128 .info = {},
129 },
130 {
131 .type = CHRE_SENSOR_TYPE_PRESSURE,
132 .sensorIndex = 0,
133 .handle = 0,
134 .isInitialized = false,
135 .enable = kEnableDefault,
136 .interval = Milliseconds(200).toRawNanoseconds(),
137 .latency = Seconds(4).toRawNanoseconds(),
138 .info = {},
139 },
140 {
141 .type = CHRE_SENSOR_TYPE_LIGHT,
142 .sensorIndex = 0,
143 .handle = 0,
144 .isInitialized = false,
145 .enable = kEnableDefault,
146 .interval = Milliseconds(200).toRawNanoseconds(),
147 .latency = 0,
148 .info = {},
149 },
150 {
151 .type = CHRE_SENSOR_TYPE_PROXIMITY,
152 .sensorIndex = 0,
153 .handle = 0,
154 .isInitialized = false,
155 .enable = kEnableDefault,
156 .interval = Milliseconds(200).toRawNanoseconds(),
157 .latency = 0,
158 .info = {},
159 },
160 {
161 .type = CHRE_SENSOR_TYPE_STEP_DETECT,
162 .sensorIndex = 0,
163 .handle = 0,
164 .isInitialized = false,
165 .enable = kEnableDefault,
166 .interval = CHRE_SENSOR_INTERVAL_DEFAULT,
167 .latency = CHRE_SENSOR_LATENCY_ASAP,
168 .info = {},
169 },
170 {
171 .type = CHRE_SENSOR_TYPE_STEP_COUNTER,
172 .sensorIndex = 0,
173 .handle = 0,
174 .isInitialized = false,
175 .enable = kEnableDefault,
176 .interval = CHRE_SENSOR_INTERVAL_DEFAULT,
177 .latency = CHRE_SENSOR_LATENCY_ASAP,
178 .info = {},
179 },
180 {
181 .type = CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE,
182 .sensorIndex = 0,
183 .handle = 0,
184 .isInitialized = false,
185 .enable = kEnableDefault,
186 .interval = Seconds(2).toRawNanoseconds(),
187 .latency = 0,
188 .info = {},
189 },
190 {
191 .type = CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE,
192 .sensorIndex = 0,
193 .handle = 0,
194 .isInitialized = false,
195 .enable = kEnableDefault,
196 .interval = Seconds(2).toRawNanoseconds(),
197 .latency = 0,
198 .info = {},
199 },
200 {
201 .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE,
202 .sensorIndex = 0,
203 .handle = 0,
204 .isInitialized = false,
205 .enable = kEnableDefault,
206 .interval = Seconds(2).toRawNanoseconds(),
207 .latency = 0,
208 .info = {},
209 },
210 {
211 .type = CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER,
212 .sensorIndex = 0,
213 .handle = 0,
214 .isInitialized = false,
215 .enable = kEnableDefault,
216 .interval = Milliseconds(80).toRawNanoseconds(),
217 .latency = Seconds(4).toRawNanoseconds(),
218 .info = {},
219 },
220 {
221 .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE,
222 .sensorIndex = 0,
223 .handle = 0,
224 .isInitialized = false,
225 .enable = kEnableDefault,
226 .interval = Milliseconds(80).toRawNanoseconds(),
227 .latency = Seconds(4).toRawNanoseconds(),
228 .info = {},
229 },
230 {
231 .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD,
232 .sensorIndex = 0,
233 .handle = 0,
234 .isInitialized = false,
235 .enable = kEnableDefault,
236 .interval = Milliseconds(80).toRawNanoseconds(),
237 .latency = Seconds(4).toRawNanoseconds(),
238 .info = {},
239 },
240 };
241
242 // Conditional logging macro
243 #define CLOGI(fmt, ...) \
244 do { \
245 if (kEnableSensorEventLogging) { \
246 LOGI(fmt, ##__VA_ARGS__); \
247 } \
248 } while (0);
249
250 // Helpers for testing InstantMotion and StationaryDetect
251 enum class MotionMode {
252 Instant,
253 Stationary,
254 };
255
256 // Storage to help access InstantMotion and StationaryDetect sensor handle and
257 // info
258 size_t motionSensorIndices[2];
259 MotionMode motionMode = MotionMode::Instant;
260
getMotionSensorIndex()261 size_t getMotionSensorIndex() {
262 motionMode = (motionMode == MotionMode::Instant) ? MotionMode::Stationary
263 : MotionMode::Instant;
264 return motionSensorIndices[static_cast<size_t>(motionMode)];
265 }
266
267 //! Used to loop through all sensors to query sensor sampling status.
268 size_t statusIndex = 0;
269
270 // Obtains 16-bit psuedo-random numbers.
getNextLfsrState()271 uint16_t getNextLfsrState() {
272 // 15-bit LFSR with feedback polynomial x^15 + x^14 + 1 gives us a
273 // pseudo-random sequence over all 32767 possible values
274 static uint16_t lfsr = 0x1337;
275 uint16_t nextBit = ((lfsr << 14) ^ (lfsr << 13)) & 0x4000;
276 lfsr = nextBit | (lfsr >> 1);
277
278 return lfsr;
279 }
280
getSensorName(uint32_t sensorHandle)281 const char *getSensorName(uint32_t sensorHandle) {
282 for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
283 if (sensors[i].handle == sensorHandle) {
284 return sensors[i].info.sensorName;
285 }
286 }
287 return nullptr;
288 }
289
handleTimerEvent(const uint32_t * ev)290 void handleTimerEvent(const uint32_t *ev) {
291 if (*ev == gFlushItTimerHandle) {
292 LOGI("FlushIt Timer Fired");
293 if (chreSensorFlushAsync(sensors[kFlushSensorIndex].handle,
294 &kFlushCookie)) {
295 gFlushItTimeoutTimerHandle =
296 chreTimerSet(kFlushItTimeout.toRawNanoseconds(),
297 &gFlushItTimeoutTimerHandle, true /* oneShot */);
298 } else {
299 LOGE("chreSensorFlushAsync failed");
300 }
301
302 } else if (*ev == gFlushItTimeoutTimerHandle) {
303 LOGE("chreSensorFlushAsync Timeout");
304
305 } else if (*ev == gBreakItTimerHandle) {
306 for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
307 SensorState &sensor = sensors[i];
308
309 bool enable = getNextLfsrState() & 0x1;
310 if (sensor.isInitialized && sensor.enable != enable) {
311 sensor.enable = enable;
312
313 bool status;
314 if (!enable) {
315 status = chreSensorConfigureModeOnly(sensor.handle,
316 CHRE_SENSOR_CONFIGURE_MODE_DONE);
317 } else {
318 enum chreSensorConfigureMode mode =
319 sensor.info.isOneShot ? CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT
320 : CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS;
321 status = chreSensorConfigure(sensor.handle, mode, sensor.interval,
322 sensor.latency);
323 }
324
325 LOGI("Configure [enable %d, status %d]: %s", enable, status,
326 sensor.info.sensorName);
327 }
328 }
329
330 gBreakItTimerHandle =
331 chreTimerSet(kBreakItPeriod.toRawNanoseconds(), &gBreakItTimerHandle,
332 true /* oneShot */);
333 }
334 }
335
handleThreeAxisEvent(const chreSensorThreeAxisData * ev,uint16_t eventType)336 void handleThreeAxisEvent(const chreSensorThreeAxisData *ev,
337 uint16_t eventType) {
338 const auto header = ev->header;
339 const auto *data = ev->readings;
340 const auto accuracy = header.accuracy;
341 uint64_t sampleTime = header.baseTimestamp;
342 uint64_t chreTime = chreGetTime();
343
344 float x = 0, y = 0, z = 0;
345 for (size_t i = 0; i < header.readingCount; i++) {
346 x += data[i].v[0];
347 y += data[i].v[1];
348 z += data[i].v[2];
349 sampleTime += data[i].timestampDelta;
350 }
351 x /= header.readingCount;
352 y /= header.readingCount;
353 z /= header.readingCount;
354
355 CLOGI("%s, %d samples: %f %f %f, accuracy: %u, t=%" PRIu64 " ms",
356 getSensorName(header.sensorHandle), header.readingCount,
357 static_cast<double>(x), static_cast<double>(y), static_cast<double>(z),
358 accuracy, header.baseTimestamp / kOneMillisecondInNanoseconds);
359
360 if (eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA) {
361 CLOGI("UncalGyro time: first %" PRIu64 " last %" PRIu64 " chre %" PRIu64
362 " delta [%" PRId64 ", %" PRId64 "]ms",
363 header.baseTimestamp, sampleTime, chreTime,
364 static_cast<int64_t>(header.baseTimestamp - chreTime) /
365 static_cast<int64_t>(kOneMillisecondInNanoseconds),
366 static_cast<int64_t>(sampleTime - chreTime) /
367 static_cast<int64_t>(kOneMillisecondInNanoseconds));
368 }
369 }
370
handleFloatEvent(const chreSensorFloatData * ev)371 void handleFloatEvent(const chreSensorFloatData *ev) {
372 const auto header = ev->header;
373
374 float v = 0;
375 for (size_t i = 0; i < header.readingCount; i++) {
376 v += ev->readings[i].value;
377 }
378 v /= header.readingCount;
379
380 CLOGI("%s, %d samples: %f, accuracy = %u, t=%" PRIu64 " ms",
381 getSensorName(header.sensorHandle), header.readingCount,
382 static_cast<double>(v), header.accuracy,
383 header.baseTimestamp / kOneMillisecondInNanoseconds);
384 }
385
handleProximityEvent(const chreSensorByteData * ev)386 void handleProximityEvent(const chreSensorByteData *ev) {
387 const auto header = ev->header;
388 const auto reading = ev->readings[0];
389 uint64_t sampleTime = header.baseTimestamp;
390 uint64_t chreTime = chreGetTime();
391
392 CLOGI("%s, %d samples: isNear %d, invalid %d, accuracy: %u",
393 getSensorName(header.sensorHandle), header.readingCount, reading.isNear,
394 reading.invalid, header.accuracy);
395
396 CLOGI("Prox time: sample %" PRIu64 " chre %" PRIu64 " delta %" PRId64 "ms",
397 header.baseTimestamp, chreTime,
398 static_cast<int64_t>(sampleTime - chreTime) / 1000000);
399
400 // Enable InstantMotion and StationaryDetect alternatively on near->far.
401 if (reading.isNear == 0 && !kBreakIt) {
402 size_t motionSensorIndex = getMotionSensorIndex();
403 bool status = chreSensorConfigure(
404 sensors[motionSensorIndex].handle, CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT,
405 CHRE_SENSOR_INTERVAL_DEFAULT, CHRE_SENSOR_LATENCY_DEFAULT);
406 LOGI("Requested %s: %s", sensors[motionSensorIndex].info.sensorName,
407 status ? "success" : "failure");
408 }
409
410 // Exercise chreGetSensorSamplingStatus on one sensor on near->far.
411 if (sensors[statusIndex].isInitialized && reading.isNear == 0) {
412 struct chreSensorSamplingStatus status;
413 bool success =
414 chreGetSensorSamplingStatus(sensors[statusIndex].handle, &status);
415 LOGI("%s success %d: enabled %d interval %" PRIu64 " latency %" PRIu64,
416 sensors[statusIndex].info.sensorName, success, status.enabled,
417 status.interval, status.latency);
418 }
419 statusIndex = (statusIndex + 1) % ARRAY_SIZE(sensors);
420 }
421
422 } // namespace
423
nanoappStart()424 bool nanoappStart() {
425 LOGI("App started on platform ID %" PRIx64, chreGetPlatformId());
426
427 for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
428 SensorState &sensor = sensors[i];
429 sensor.isInitialized =
430 chreSensorFind(sensor.type, sensor.sensorIndex, &sensor.handle);
431 LOGI("Sensor %zu initialized: %s with handle %" PRIu32, i,
432 sensor.isInitialized ? "true" : "false", sensor.handle);
433
434 if (sensor.type == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT) {
435 motionSensorIndices[static_cast<size_t>(MotionMode::Instant)] = i;
436 } else if (sensor.type == CHRE_SENSOR_TYPE_STATIONARY_DETECT) {
437 motionSensorIndices[static_cast<size_t>(MotionMode::Stationary)] = i;
438 }
439
440 if (sensor.isInitialized) {
441 // Get sensor info
442 chreSensorInfo &info = sensor.info;
443 bool infoStatus = chreGetSensorInfo(sensor.handle, &info);
444 if (infoStatus) {
445 LOGI("SensorInfo: %s, Type=%" PRIu8
446 " OnChange=%d OneShot=%d Passive=%d "
447 "minInterval=%" PRIu64 "nsec",
448 info.sensorName, info.sensorType, info.isOnChange, info.isOneShot,
449 info.supportsPassiveMode, info.minInterval);
450 } else {
451 LOGE("chreGetSensorInfo failed");
452 }
453
454 // Subscribe to sensors
455 if (sensor.enable) {
456 float odrHz = 1e9f / static_cast<float>(sensor.interval);
457 float latencySec = static_cast<float>(sensor.latency) / 1e9f;
458 bool status = chreSensorConfigure(sensor.handle,
459 CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS,
460 sensor.interval, sensor.latency);
461 LOGI("Requested data: odr %f Hz, latency %f sec, %s",
462 static_cast<double>(odrHz), static_cast<double>(latencySec),
463 status ? "success" : "failure");
464 }
465 }
466 }
467
468 // Set timer for BreakIt test.
469 if (kBreakIt) {
470 gBreakItTimerHandle =
471 chreTimerSet(kBreakItPeriod.toRawNanoseconds(), &gBreakItTimerHandle,
472 true /* oneShot */);
473 }
474
475 if (kFlushIt) {
476 // Triger a flush half way through the target sensor latency
477 gFlushItTimerHandle =
478 chreTimerSet(sensors[kFlushSensorIndex].latency / 2,
479 &gFlushItTimerHandle, true /* oneShot */);
480 }
481
482 return true;
483 }
484
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)485 void nanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
486 const void *eventData) {
487 UNUSED_VAR(senderInstanceId);
488
489 switch (eventType) {
490 case CHRE_EVENT_SENSOR_ACCELEROMETER_DATA:
491 case CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA:
492 case CHRE_EVENT_SENSOR_GYROSCOPE_DATA:
493 case CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA:
494 case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA:
495 case CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA:
496 handleThreeAxisEvent(
497 static_cast<const chreSensorThreeAxisData *>(eventData), eventType);
498 break;
499
500 case CHRE_EVENT_SENSOR_PRESSURE_DATA:
501 case CHRE_EVENT_SENSOR_LIGHT_DATA:
502 case CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA:
503 case CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA:
504 case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_TEMPERATURE_DATA:
505 handleFloatEvent(static_cast<const chreSensorFloatData *>(eventData));
506 break;
507
508 case CHRE_EVENT_SENSOR_PROXIMITY_DATA:
509 handleProximityEvent(static_cast<const chreSensorByteData *>(eventData));
510 break;
511
512 case CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA:
513 case CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA:
514 case CHRE_EVENT_SENSOR_STEP_DETECT_DATA: {
515 const auto *ev = static_cast<const chreSensorOccurrenceData *>(eventData);
516 const auto header = ev->header;
517
518 CLOGI("%s, %d samples, accuracy: %u", getSensorName(header.sensorHandle),
519 header.readingCount, header.accuracy);
520 break;
521 }
522
523 case CHRE_EVENT_SENSOR_STEP_COUNTER_DATA: {
524 const auto *ev = static_cast<const chreSensorUint64Data *>(eventData);
525 const auto header = ev->header;
526 const uint64_t reading = ev->readings[header.readingCount - 1].value;
527
528 CLOGI("%s, %" PRIu16 " samples: latest %" PRIu64,
529 getSensorName(header.sensorHandle), header.readingCount, reading);
530 break;
531 }
532
533 case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
534 const auto *ev =
535 static_cast<const chreSensorSamplingStatusEvent *>(eventData);
536
537 CLOGI("Sampling Change: handle %" PRIu32 ", status: interval %" PRIu64
538 " latency %" PRIu64 " enabled %d",
539 ev->sensorHandle, ev->status.interval, ev->status.latency,
540 ev->status.enabled);
541 break;
542 }
543
544 case CHRE_EVENT_TIMER:
545 if (kBreakIt || kFlushIt) {
546 handleTimerEvent(static_cast<const uint32_t *>(eventData));
547 } else {
548 LOGE("Timer event received with kBreakIt and kFlushIt disabled");
549 }
550 break;
551
552 case CHRE_EVENT_SENSOR_FLUSH_COMPLETE: {
553 const auto *ev =
554 static_cast<const chreSensorFlushCompleteEvent *>(eventData);
555 chreTimerCancel(gFlushItTimeoutTimerHandle);
556
557 LOGI("Flush Complete: handle %" PRIu32 ", errorCode: %d",
558 ev->sensorHandle, ev->errorCode);
559 break;
560 }
561
562 default:
563 LOGW("Unhandled event %d", eventType);
564 break;
565 }
566 }
567
nanoappEnd()568 void nanoappEnd() {
569 LOGI("Stopped");
570 }
571
572 #ifdef CHRE_NANOAPP_INTERNAL
573 } // anonymous namespace
574 } // namespace chre
575
576 #include "chre/platform/static_nanoapp_init.h"
577 #include "chre/util/nanoapp/app_id.h"
578 #include "chre/util/system/napp_permissions.h"
579
580 CHRE_STATIC_NANOAPP_INIT(SensorWorld, chre::kSensorWorldAppId, 0,
581 chre::NanoappPermissions::CHRE_PERMS_NONE);
582 #endif // CHRE_NANOAPP_INTERNAL
583