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