• 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/nanoapp/sensor.h"
23 #include "chre/util/time.h"
24 
25 #define LOG_TAG "[SensorWorld]"
26 
27 #ifdef CHRE_NANOAPP_INTERNAL
28 namespace chre {
29 namespace {
30 #endif  // CHRE_NANOAPP_INTERNAL
31 
32 namespace {
33 
34 //! Enable/disable all sensors by default.
35 // This allows disabling all sensens by default and enabling only targeted
36 // sensors for testing by locally overriding 'enable' field in SensorState.
37 constexpr bool kEnableDefault = true;
38 
39 struct SensorState {
40   const uint8_t type;
41   uint32_t handle;
42   bool isInitialized;
43   bool enable;
44   uint64_t interval;  // nsec
45   uint64_t latency;  // nsec
46   chreSensorInfo info;
47 };
48 
49 SensorState sensors[] = {
50   { .type = CHRE_SENSOR_TYPE_ACCELEROMETER,
51     .enable = kEnableDefault,
52     .interval = Milliseconds(80).toRawNanoseconds(),
53     .latency = Seconds(4).toRawNanoseconds(),
54   },
55   { .type = CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT,
56     .enable = false,  // InstantMotion is triggered by Prox
57   },
58   { .type = CHRE_SENSOR_TYPE_STATIONARY_DETECT,
59     .enable = false,  // StationaryDetect is triggered by Prox
60   },
61   { .type = CHRE_SENSOR_TYPE_GYROSCOPE,
62     .enable = kEnableDefault,
63     .interval = Milliseconds(80).toRawNanoseconds(),
64     .latency = Seconds(4).toRawNanoseconds(),
65   },
66   { .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD,
67     .enable = kEnableDefault,
68     .interval = Milliseconds(80).toRawNanoseconds(),
69     .latency = Seconds(4).toRawNanoseconds(),
70   },
71   { .type = CHRE_SENSOR_TYPE_PRESSURE,
72     .enable = kEnableDefault,
73     .interval = Milliseconds(200).toRawNanoseconds(),
74     .latency = Seconds(4).toRawNanoseconds(),
75   },
76   { .type = CHRE_SENSOR_TYPE_LIGHT,
77     .enable = kEnableDefault,
78     .interval = Milliseconds(200).toRawNanoseconds(),
79     .latency = 0,
80   },
81   { .type = CHRE_SENSOR_TYPE_PROXIMITY,
82     .enable = kEnableDefault,
83     .interval = Milliseconds(200).toRawNanoseconds(),
84     .latency = 0,
85   },
86   { .type = CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE,
87     .enable = kEnableDefault,
88     .interval = Seconds(2).toRawNanoseconds(),
89     .latency = 0,
90   },
91   { .type = CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE,
92     .enable = kEnableDefault,
93     .interval = Seconds(2).toRawNanoseconds(),
94     .latency = 0,
95   },
96   { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER,
97     .enable = kEnableDefault,
98     .interval = Milliseconds(80).toRawNanoseconds(),
99     .latency = Seconds(4).toRawNanoseconds(),
100   },
101   { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE,
102     .enable = kEnableDefault,
103     .interval = Milliseconds(80).toRawNanoseconds(),
104     .latency = Seconds(4).toRawNanoseconds(),
105   },
106   { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD,
107     .enable = kEnableDefault,
108     .interval = Milliseconds(80).toRawNanoseconds(),
109     .latency = Seconds(4).toRawNanoseconds(),
110   },
111 };
112 
113 // Helpers for testing InstantMotion and StationaryDetect
114 enum class MotionMode {
115   Instant,
116   Stationary,
117 };
118 
119 // Storage to help access InstantMotion and StationaryDetect sensor handle and
120 // info
121 size_t motionSensorIndices[2];
122 MotionMode motionMode = MotionMode::Instant;
123 
getMotionSensorIndex()124 size_t getMotionSensorIndex() {
125   motionMode = (motionMode == MotionMode::Instant) ?
126       MotionMode::Stationary : MotionMode::Instant;
127   return motionSensorIndices[static_cast<size_t>(motionMode)];
128 }
129 
130 size_t statusIndex = 0;
131 
132 } // namespace
133 
nanoappStart()134 bool nanoappStart() {
135   LOGI("App started on platform ID %" PRIx64, chreGetPlatformId());
136 
137   for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
138     SensorState& sensor = sensors[i];
139     sensor.isInitialized = chreSensorFindDefault(sensor.type, &sensor.handle);
140     LOGI("Sensor %d initialized: %s with handle %" PRIu32,
141          i, sensor.isInitialized ? "true" : "false", sensor.handle);
142 
143     if (sensor.type == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT) {
144       motionSensorIndices[static_cast<size_t>(MotionMode::Instant)] = i;
145     } else if (sensor.type == CHRE_SENSOR_TYPE_STATIONARY_DETECT) {
146       motionSensorIndices[static_cast<size_t>(MotionMode::Stationary)] = i;
147     }
148 
149     if (sensor.isInitialized) {
150       // Get sensor info
151       chreSensorInfo& info = sensor.info;
152       bool infoStatus = chreGetSensorInfo(sensor.handle, &info);
153       if (infoStatus) {
154         LOGI("SensorInfo: %s, Type=%" PRIu8 " OnChange=%d"
155              " OneShot=%d minInterval=%" PRIu64 "nsec",
156              info.sensorName, info.sensorType, info.isOnChange,
157              info.isOneShot, info.minInterval);
158       } else {
159         LOGE("chreGetSensorInfo failed");
160       }
161 
162       // Subscribe to sensors
163       if (sensor.enable) {
164         float odrHz = 1e9f / sensor.interval;
165         float latencySec = sensor.latency / 1e9f;
166         bool status = chreSensorConfigure(sensor.handle,
167             CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS, sensor.interval,
168             sensor.latency);
169         LOGI("Requested data: odr %f Hz, latency %f sec, %s",
170              odrHz, latencySec, status ? "success" : "failure");
171       }
172     }
173   }
174 
175   return true;
176 }
177 
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)178 void nanoappHandleEvent(uint32_t senderInstanceId,
179                         uint16_t eventType,
180                         const void *eventData) {
181   uint64_t chreTime = chreGetTime();
182   uint64_t sampleTime;
183   switch (eventType) {
184     case CHRE_EVENT_SENSOR_ACCELEROMETER_DATA:
185     case CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA:
186     case CHRE_EVENT_SENSOR_GYROSCOPE_DATA:
187     case CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA:
188     case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA:
189     case CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA: {
190       const auto *ev = static_cast<const chreSensorThreeAxisData *>(eventData);
191       const auto header = ev->header;
192       const auto *data = ev->readings;
193       sampleTime = header.baseTimestamp;
194 
195       float x = 0, y = 0, z = 0;
196       for (size_t i = 0; i < header.readingCount; i++) {
197         x += data[i].v[0];
198         y += data[i].v[1];
199         z += data[i].v[2];
200         sampleTime += data[i].timestampDelta;
201       }
202       x /= header.readingCount;
203       y /= header.readingCount;
204       z /= header.readingCount;
205 
206       LOGI("%s, %d samples: %f %f %f",
207            getSensorNameForEventType(eventType), header.readingCount, x, y, z);
208 
209       if (eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA) {
210         LOGI("UncalGyro time: first %" PRIu64 " last %" PRIu64 " chre %" PRIu64
211              " delta [%" PRId64 ", %" PRId64 "]ms",
212              header.baseTimestamp, sampleTime, chreTime,
213              static_cast<int64_t>(header.baseTimestamp - chreTime) / 1000000,
214              static_cast<int64_t>(sampleTime - chreTime) / 1000000);
215       }
216       break;
217     }
218 
219     case CHRE_EVENT_SENSOR_PRESSURE_DATA:
220     case CHRE_EVENT_SENSOR_LIGHT_DATA:
221     case CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA:
222     case CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA: {
223       const auto *ev = static_cast<const chreSensorFloatData *>(eventData);
224       const auto header = ev->header;
225 
226       float v = 0;
227       for (size_t i = 0; i < header.readingCount; i++) {
228         v += ev->readings[i].value;
229       }
230       v /= header.readingCount;
231 
232       LOGI("%s, %d samples: %f",
233            getSensorNameForEventType(eventType), header.readingCount, v);
234       break;
235     }
236 
237     case CHRE_EVENT_SENSOR_PROXIMITY_DATA: {
238       const auto *ev = static_cast<const chreSensorByteData *>(eventData);
239       const auto header = ev->header;
240       const auto reading = ev->readings[0];
241       sampleTime = header.baseTimestamp;
242 
243       LOGI("%s, %d samples: isNear %d, invalid %d",
244            getSensorNameForEventType(eventType), header.readingCount,
245            reading.isNear, reading.invalid);
246 
247       LOGI("Prox time: sample %" PRIu64 " chre %" PRIu64 " delta %" PRId64 "ms",
248            header.baseTimestamp, chreTime,
249            static_cast<int64_t>(sampleTime - chreTime) / 1000000);
250 
251       // Enable InstantMotion and StationaryDetect alternatively on near->far.
252       if (reading.isNear == 0) {
253         size_t motionSensorIndex = getMotionSensorIndex();
254         bool status = chreSensorConfigure(sensors[motionSensorIndex].handle,
255             CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT,
256             CHRE_SENSOR_INTERVAL_DEFAULT,
257             CHRE_SENSOR_LATENCY_DEFAULT);
258         LOGI("Requested %s: %s", sensors[motionSensorIndex].info.sensorName,
259               status ? "success" : "failure");
260       }
261 
262       // Exercise chreGetSensorSamplingStatus on one sensor on near->far.
263       if (sensors[statusIndex].isInitialized && reading.isNear == 0) {
264         struct chreSensorSamplingStatus status;
265         bool success = chreGetSensorSamplingStatus(sensors[statusIndex].handle,
266                                                    &status);
267         LOGI("%s success %d: enabled %d interval %" PRIu64 " latency %" PRIu64,
268              sensors[statusIndex].info.sensorName, success, status.enabled,
269              status.interval, status.latency);
270       }
271       statusIndex = (statusIndex + 1) % ARRAY_SIZE(sensors);
272       break;
273     }
274 
275     case CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA:
276     case CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA: {
277       const auto *ev = static_cast<const chreSensorOccurrenceData *>(eventData);
278       const auto header = ev->header;
279 
280       LOGI("%s, %d samples",
281            getSensorNameForEventType(eventType), header.readingCount);
282       break;
283     }
284 
285     case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
286       const auto *ev = static_cast<const chreSensorSamplingStatusEvent *>(
287           eventData);
288 
289       LOGI("Sampling Change: handle %" PRIu32 ", status: interval %" PRIu64
290            " latency %" PRIu64 " enabled %d",
291            ev->sensorHandle, ev->status.interval, ev->status.latency,
292            ev->status.enabled);
293       break;
294     }
295 
296 
297     default:
298       LOGW("Unhandled event %d", eventType);
299       break;
300   }
301 }
302 
nanoappEnd()303 void nanoappEnd() {
304   LOGI("Stopped");
305 }
306 
307 #ifdef CHRE_NANOAPP_INTERNAL
308 }  // anonymous namespace
309 }  // namespace chre
310 
311 #include "chre/util/nanoapp/app_id.h"
312 #include "chre/platform/static_nanoapp_init.h"
313 
314 CHRE_STATIC_NANOAPP_INIT(SensorWorld, chre::kSensorWorldAppId, 0);
315 #endif  // CHRE_NANOAPP_INTERNAL
316