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