• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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