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