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