• 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   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