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 struct SensorState {
35 const uint8_t type;
36 uint32_t handle;
37 bool isInitialized;
38 bool enable;
39 uint64_t interval; // nsec
40 uint64_t latency; // nsec
41 chreSensorInfo info;
42 };
43
44 SensorState sensors[] = {
45 { .type = CHRE_SENSOR_TYPE_ACCELEROMETER,
46 .enable = true,
47 .interval = Milliseconds(80).toRawNanoseconds(),
48 .latency = Seconds(4).toRawNanoseconds(),
49 },
50 { .type = CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT,
51 .enable = false,
52 },
53 { .type = CHRE_SENSOR_TYPE_STATIONARY_DETECT,
54 .enable = false,
55 },
56 { .type = CHRE_SENSOR_TYPE_GYROSCOPE,
57 .enable = true,
58 .interval = Milliseconds(80).toRawNanoseconds(),
59 .latency = Seconds(4).toRawNanoseconds(),
60 },
61 { .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD,
62 .enable = true,
63 .interval = Milliseconds(80).toRawNanoseconds(),
64 .latency = Seconds(4).toRawNanoseconds(),
65 },
66 { .type = CHRE_SENSOR_TYPE_PRESSURE,
67 .enable = true,
68 .interval = Milliseconds(200).toRawNanoseconds(),
69 .latency = Seconds(4).toRawNanoseconds(),
70 },
71 { .type = CHRE_SENSOR_TYPE_LIGHT,
72 .enable = true,
73 .interval = Milliseconds(200).toRawNanoseconds(),
74 .latency = 0,
75 },
76 { .type = CHRE_SENSOR_TYPE_PROXIMITY,
77 .enable = true,
78 .interval = Milliseconds(200).toRawNanoseconds(),
79 .latency = 0,
80 },
81 { .type = CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE,
82 .enable = true,
83 .interval = Seconds(2).toRawNanoseconds(),
84 .latency = 0,
85 },
86 { .type = CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE,
87 .enable = true,
88 .interval = Seconds(2).toRawNanoseconds(),
89 .latency = 0,
90 },
91 { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER,
92 .enable = true,
93 .interval = Milliseconds(80).toRawNanoseconds(),
94 .latency = Seconds(4).toRawNanoseconds(),
95 },
96 { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE,
97 .enable = true,
98 .interval = Milliseconds(80).toRawNanoseconds(),
99 .latency = Seconds(4).toRawNanoseconds(),
100 },
101 { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD,
102 .enable = true,
103 .interval = Milliseconds(80).toRawNanoseconds(),
104 .latency = Seconds(4).toRawNanoseconds(),
105 },
106 };
107
108 // Helpers for testing InstantMotion and StationaryDetect
109 enum class MotionMode {
110 Instant,
111 Stationary,
112 };
113
114 // Storage to help access InstantMotion and StationaryDetect sensor handle and
115 // info
116 static size_t motionSensorIndices[2];
117 static MotionMode motionMode = MotionMode::Instant;
118
getMotionSensorIndex()119 size_t getMotionSensorIndex() {
120 motionMode = (motionMode == MotionMode::Instant) ?
121 MotionMode::Stationary : MotionMode::Instant;
122 return motionSensorIndices[static_cast<size_t>(motionMode)];
123 }
124
125 } // namespace
126
nanoappStart()127 bool nanoappStart() {
128 LOGI("App started on platform ID %" PRIx64, chreGetPlatformId());
129
130 for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
131 SensorState& sensor = sensors[i];
132 sensor.isInitialized = chreSensorFindDefault(sensor.type, &sensor.handle);
133 LOGI("Sensor %d initialized: %s with handle %" PRIu32,
134 i, sensor.isInitialized ? "true" : "false", sensor.handle);
135
136 if (sensor.type == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT) {
137 motionSensorIndices[static_cast<size_t>(MotionMode::Instant)] = i;
138 } else if (sensor.type == CHRE_SENSOR_TYPE_STATIONARY_DETECT) {
139 motionSensorIndices[static_cast<size_t>(MotionMode::Stationary)] = i;
140 }
141
142 if (sensor.isInitialized) {
143 // Get sensor info
144 chreSensorInfo& info = sensor.info;
145 bool infoStatus = chreGetSensorInfo(sensor.handle, &info);
146 if (infoStatus) {
147 LOGI("SensorInfo: %s, Type=%" PRIu8 " OnChange=%d"
148 " OneShot=%d minInterval=%" PRIu64 "nsec",
149 info.sensorName, info.sensorType, info.isOnChange,
150 info.isOneShot, info.minInterval);
151 } else {
152 LOGE("chreGetSensorInfo failed");
153 }
154
155 // Subscribe to sensors
156 if (sensor.enable) {
157 float odrHz = 1e9 / sensor.interval;
158 float latencySec = sensor.latency / 1e9;
159 bool status = chreSensorConfigure(sensor.handle,
160 CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS, sensor.interval,
161 sensor.latency);
162 LOGI("Requested data: odr %f Hz, latency %f sec, %s",
163 odrHz, latencySec, status ? "success" : "failure");
164 }
165 }
166 }
167
168 return true;
169 }
170
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)171 void nanoappHandleEvent(uint32_t senderInstanceId,
172 uint16_t eventType,
173 const void *eventData) {
174 switch (eventType) {
175 case CHRE_EVENT_SENSOR_ACCELEROMETER_DATA:
176 case CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA:
177 case CHRE_EVENT_SENSOR_GYROSCOPE_DATA:
178 case CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA:
179 case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA:
180 case CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA: {
181 const auto *ev = static_cast<const chreSensorThreeAxisData *>(eventData);
182 const auto header = ev->header;
183 const auto *data = ev->readings;
184
185 float x = 0, y = 0, z = 0;
186 for (size_t i = 0; i < header.readingCount; i++) {
187 x += data[i].v[0];
188 y += data[i].v[1];
189 z += data[i].v[2];
190 }
191 x /= header.readingCount;
192 y /= header.readingCount;
193 z /= header.readingCount;
194
195 LOGI("%s, %d samples: %f %f %f",
196 getSensorNameForEventType(eventType), header.readingCount, x, y, z);
197 break;
198 }
199
200 case CHRE_EVENT_SENSOR_PRESSURE_DATA:
201 case CHRE_EVENT_SENSOR_LIGHT_DATA:
202 case CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA:
203 case CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA: {
204 const auto *ev = static_cast<const chreSensorFloatData *>(eventData);
205 const auto header = ev->header;
206
207 float v = 0;
208 for (size_t i = 0; i < header.readingCount; i++) {
209 v += ev->readings[i].value;
210 }
211 v /= header.readingCount;
212
213 LOGI("%s, %d samples: %f",
214 getSensorNameForEventType(eventType), header.readingCount, v);
215 break;
216 }
217
218 case CHRE_EVENT_SENSOR_PROXIMITY_DATA: {
219 const auto *ev = static_cast<const chreSensorByteData *>(eventData);
220 const auto header = ev->header;
221 const auto reading = ev->readings[0];
222
223 LOGI("%s, %d samples: isNear %d, invalid %d",
224 getSensorNameForEventType(eventType), header.readingCount,
225 reading.isNear, reading.invalid);
226
227 // Enable InstantMotion and StationaryDetect alternatively on near->far.
228 if (reading.isNear == 0) {
229 size_t motionSensorIndex = getMotionSensorIndex();
230 bool status = chreSensorConfigure(sensors[motionSensorIndex].handle,
231 CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT,
232 CHRE_SENSOR_INTERVAL_DEFAULT,
233 CHRE_SENSOR_LATENCY_DEFAULT);
234 LOGI("Requested %s: %s", sensors[motionSensorIndex].info.sensorName,
235 status ? "success" : "failure");
236 }
237 break;
238 }
239
240 case CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA:
241 case CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA: {
242 const auto *ev = static_cast<const chreSensorOccurrenceData *>(eventData);
243 const auto header = ev->header;
244
245 LOGI("%s, %d samples",
246 getSensorNameForEventType(eventType), header.readingCount);
247 break;
248 }
249
250 default:
251 LOGW("Unhandled event %d", eventType);
252 break;
253 }
254 }
255
nanoappEnd()256 void nanoappEnd() {
257 LOGI("Stopped");
258 }
259
260 #ifdef CHRE_NANOAPP_INTERNAL
261 } // anonymous namespace
262 } // namespace chre
263
264 #include "chre/util/nanoapp/app_id.h"
265 #include "chre/platform/static_nanoapp_init.h"
266
267 CHRE_STATIC_NANOAPP_INIT(SensorWorld, chre::kSensorWorldAppId, 0);
268 #endif // CHRE_NANOAPP_INTERNAL
269