1 /*
2 * Copyright (C) 2019 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 "request_manager.h"
18
19 #include "chre/util/macros.h"
20 #include "chre/util/nanoapp/audio.h"
21 #include "chre/util/nested_data_ptr.h"
22 #include "generated/chre_power_test_generated.h"
23
24 namespace chre {
25 namespace {
26
27 //! List of all sensor types that can be interacted with from the nanoapp.
28 constexpr uint8_t kAllSensorTypes[] = {
29 CHRE_SENSOR_TYPE_ACCELEROMETER,
30 CHRE_SENSOR_TYPE_GYROSCOPE,
31 CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE,
32 CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD,
33 CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD,
34 CHRE_SENSOR_TYPE_PRESSURE,
35 CHRE_SENSOR_TYPE_LIGHT,
36 CHRE_SENSOR_TYPE_PROXIMITY,
37 CHRE_SENSOR_TYPE_STEP_DETECT,
38 CHRE_SENSOR_TYPE_STEP_COUNTER,
39 CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER,
40 CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE,
41 CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE,
42 CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE,
43 CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT,
44 CHRE_SENSOR_TYPE_STATIONARY_DETECT,
45 };
46
47 /**
48 * Retrieve the configure mode for the given sensor type.
49 *
50 * @param sensorType The type of the sensor
51 * @return The sensor configure mode for the given sensor type
52 */
getModeForSensorType(uint8_t sensorType)53 chreSensorConfigureMode getModeForSensorType(uint8_t sensorType) {
54 chreSensorConfigureMode mode;
55 switch (sensorType) {
56 case CHRE_SENSOR_TYPE_ACCELEROMETER:
57 case CHRE_SENSOR_TYPE_GYROSCOPE:
58 case CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE:
59 case CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD:
60 case CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD:
61 case CHRE_SENSOR_TYPE_PRESSURE:
62 case CHRE_SENSOR_TYPE_LIGHT:
63 case CHRE_SENSOR_TYPE_PROXIMITY:
64 case CHRE_SENSOR_TYPE_STEP_DETECT:
65 case CHRE_SENSOR_TYPE_STEP_COUNTER:
66 case CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER:
67 case CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE:
68 case CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE:
69 case CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE:
70 mode = CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS;
71 break;
72 case CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT:
73 case CHRE_SENSOR_TYPE_STATIONARY_DETECT:
74 mode = CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT;
75 break;
76 default:
77 LOGE("Mode requested for unhandled sensor type %" PRIu8
78 " defaulting to continuous",
79 sensorType);
80 mode = CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS;
81 }
82 return mode;
83 }
84
85 /**
86 * Verifies a given message from the host is a valid message to the nanoapp.
87 *
88 * @param hostMessage message being delivered from the host
89 * @param verifiedMessage if verification is successful, contains the decoded
90 * message from the host. Otherwise, is uninitialized.
91 * @return true if the message was verified to be a valid.
92 */
93 template <class MessageClass>
verifyMessage(const chreMessageFromHostData & hostMessage,const MessageClass ** verifiedMessage)94 bool verifyMessage(const chreMessageFromHostData &hostMessage,
95 const MessageClass **verifiedMessage) {
96 flatbuffers::Verifier verifier(
97 static_cast<const uint8_t *>(hostMessage.message),
98 hostMessage.messageSize);
99 bool verified = verifier.VerifyBuffer<MessageClass>(nullptr);
100 if (verified) {
101 *verifiedMessage = flatbuffers::GetRoot<MessageClass>(hostMessage.message);
102 } else {
103 LOGE("Failed to verify %s message from host",
104 power_test::EnumNameMessageType(
105 static_cast<power_test::MessageType>(hostMessage.messageType)));
106 }
107 return verified;
108 }
109
110 } // namespace
111
112 using power_test::AudioRequestMessage;
113 using power_test::BreakItMessage;
114 using power_test::CellQueryMessage;
115 using power_test::GnssLocationMessage;
116 using power_test::GnssMeasurementMessage;
117 using power_test::MessageType;
118 using power_test::NanoappResponseMessage;
119 using power_test::SensorRequestMessage;
120 using power_test::TimerMessage;
121 using power_test::WifiScanMessage;
122
requestTimer(bool enable,TimerType type,Nanoseconds delay)123 bool RequestManager::requestTimer(bool enable, TimerType type,
124 Nanoseconds delay) {
125 bool success = false;
126 if (enable) {
127 // Stop previous request if active.
128 chreTimerCancel(mTimerIds[type]);
129 mTimerIds[type] = CHRE_TIMER_INVALID;
130
131 // Set a timer for the new request.
132 NestedDataPtr<TimerType> timerType(type);
133 uint32_t timerId =
134 chreTimerSet(delay.toRawNanoseconds(), timerType, false /* oneShot */);
135 if (timerId != CHRE_TIMER_INVALID) {
136 success = true;
137 mTimerIds[type] = timerId;
138 }
139 } else {
140 success = chreTimerCancel(mTimerIds[type]);
141 mTimerIds[type] = CHRE_TIMER_INVALID;
142 }
143 LOGI("RequestTimer success %d, enable %d, type %d, delay %" PRIu64, success,
144 enable, type, delay.toRawNanoseconds());
145 return success;
146 }
147
wifiTimerCallback() const148 void RequestManager::wifiTimerCallback() const {
149 struct chreWifiScanParams params = {};
150 params.scanType = mWifiScanType;
151 params.radioChainPref = mWifiRadioChain;
152 params.channelSet = mWifiChannelSet;
153 bool success = chreWifiRequestScanAsync(¶ms, nullptr /*cookie*/);
154 LOGI("Requested WiFi - success %d, scanType %" PRIu8 " radioChain %" PRIu8
155 " channelSet %" PRIu8,
156 success, params.scanType, params.radioChainPref, params.channelSet);
157 }
158
requestGnssLocation(bool enable,uint32_t scanIntervalMillis,uint32_t minTimeToNextFixMillis) const159 bool RequestManager::requestGnssLocation(
160 bool enable, uint32_t scanIntervalMillis,
161 uint32_t minTimeToNextFixMillis) const {
162 bool success;
163 if (enable) {
164 success = chreGnssLocationSessionStartAsync(
165 scanIntervalMillis, minTimeToNextFixMillis, nullptr /* cookie */);
166 } else {
167 success = chreGnssLocationSessionStopAsync(nullptr /* cookie */);
168 }
169 LOGI("RequestGnss success %d, enable %d, scanIntervalMillis %" PRIu32
170 " minTimeToNextFixMillis %" PRIu32,
171 success, enable, scanIntervalMillis, minTimeToNextFixMillis);
172 return success;
173 }
174
requestGnssMeasurement(bool enable,uint32_t intervalMillis) const175 bool RequestManager::requestGnssMeasurement(bool enable,
176 uint32_t intervalMillis) const {
177 bool success;
178 if (enable) {
179 success = chreGnssMeasurementSessionStartAsync(intervalMillis,
180 nullptr /* cookie */);
181 } else {
182 success = chreGnssMeasurementSessionStopAsync(nullptr /* cookie */);
183 }
184 LOGI("RequestGnssMeasurement success %d, enable %d, intervalMillis %" PRIu32,
185 success, enable, intervalMillis);
186 return success;
187 }
188
cellTimerCallback() const189 void RequestManager::cellTimerCallback() const {
190 bool success = chreWwanGetCellInfoAsync(nullptr /* cookie */);
191 LOGI("Requested Cell - success %d", success);
192 }
193
requestAudio(bool enable,uint64_t bufferDurationNs) const194 bool RequestManager::requestAudio(bool enable,
195 uint64_t bufferDurationNs) const {
196 bool success;
197
198 if (enable) {
199 // Only request audio data from the first source
200 // TODO: Request audio data from all available sources (or allow configuring
201 // which source to sample from)
202 success = chreAudioConfigureSource(0 /* handle */, true /* enable */,
203 bufferDurationNs, bufferDurationNs);
204 } else {
205 success = chreAudioConfigureSource(0 /* handle */, false /* enable */,
206 0 /* bufferDuration */,
207 0 /* deliveryInterval */);
208 }
209 LOGI("RequestAudio success %d, enable %d, bufferDurationNs %" PRIu64, success,
210 enable, bufferDurationNs);
211 return success;
212 }
213
requestSensor(bool enable,uint8_t sensorType,uint64_t samplingIntervalNs,uint64_t latencyNs) const214 bool RequestManager::requestSensor(bool enable, uint8_t sensorType,
215 uint64_t samplingIntervalNs,
216 uint64_t latencyNs) const {
217 uint32_t sensorHandle;
218 bool success = chreSensorFindDefault(sensorType, &sensorHandle);
219
220 if (success) {
221 if (enable) {
222 success =
223 chreSensorConfigure(sensorHandle, getModeForSensorType(sensorType),
224 samplingIntervalNs, latencyNs);
225 } else {
226 success = chreSensorConfigureModeOnly(sensorHandle,
227 CHRE_SENSOR_CONFIGURE_MODE_DONE);
228 }
229 }
230
231 LOGI("RequestSensor success %d, enable %d, sensorType %" PRIu8
232 " samplingIntervalNs %" PRIu64 " latencyNs %" PRIu64,
233 success, enable, sensorType, samplingIntervalNs, latencyNs);
234 return success;
235 }
236
requestAllSensors(bool enable) const237 bool RequestManager::requestAllSensors(bool enable) const {
238 bool success = true;
239 uint32_t sensorHandle;
240 struct chreSensorInfo sensorInfo;
241 for (uint8_t i = 0; i < ARRAY_SIZE(kAllSensorTypes); i++) {
242 success &= chreSensorFindDefault(kAllSensorTypes[i], &sensorHandle) &&
243 chreGetSensorInfo(sensorHandle, &sensorInfo) &&
244 requestSensor(enable, kAllSensorTypes[i], sensorInfo.minInterval,
245 CHRE_SENSOR_LATENCY_ASAP);
246 }
247
248 LOGI("requestAllSensors success %d enable %d", success, enable);
249 return success;
250 }
251
requestAudioAtFastestRate(bool enable) const252 bool RequestManager::requestAudioAtFastestRate(bool enable) const {
253 struct chreAudioSource audioSource;
254 bool success = chreAudioGetSource(0 /* handle */, &audioSource);
255 if (success) {
256 LOGI("Found audio source '%s' with %" PRIu32 "Hz %s data", audioSource.name,
257 audioSource.sampleRate,
258 chre::getChreAudioFormatString(audioSource.format));
259 LOGI(" buffer duration: [%" PRIu64 "ns, %" PRIu64 "ns]",
260 audioSource.minBufferDuration, audioSource.maxBufferDuration);
261 success &= requestAudio(enable, audioSource.minBufferDuration);
262 }
263
264 LOGI("requestAudioAtFastestRate success %d enable %d", success, enable);
265 return success;
266 }
267
requestBreakIt(bool enable)268 bool RequestManager::requestBreakIt(bool enable) {
269 bool success = requestTimer(enable, TimerType::WIFI, Seconds(1));
270 success &= requestGnssLocation(enable, chre::kOneSecondInNanoseconds,
271 0 /* minTimeToNextFixMillis */);
272 success &= requestTimer(enable, TimerType::CELL, Seconds(1));
273 success &= requestAudioAtFastestRate(enable);
274 success &= requestAllSensors(enable);
275 LOGI("RequestBreakIt success %d enable %d", success, enable);
276 return success;
277 }
278
handleTimerEvent(const void * cookie) const279 void RequestManager::handleTimerEvent(const void *cookie) const {
280 if (cookie != nullptr) {
281 NestedDataPtr<TimerType> timerType(const_cast<void *>(cookie));
282 switch (timerType.data) {
283 case TimerType::WAKEUP:
284 LOGI("Received a wakeup timer event");
285 break;
286 case TimerType::WIFI:
287 wifiTimerCallback();
288 break;
289 case TimerType::CELL:
290 cellTimerCallback();
291 break;
292 default:
293 LOGE("Invalid timer type received %d", timerType.data);
294 }
295 }
296 }
297
handleMessageFromHost(const chreMessageFromHostData & hostMessage)298 bool RequestManager::handleMessageFromHost(
299 const chreMessageFromHostData &hostMessage) {
300 bool success = false;
301 if (hostMessage.message == nullptr) {
302 LOGE("Host message from %" PRIu16 " has empty message",
303 hostMessage.hostEndpoint);
304 } else {
305 switch (static_cast<MessageType>(hostMessage.messageType)) {
306 case MessageType::TIMER_TEST: {
307 const TimerMessage *msg;
308 if (verifyMessage<TimerMessage>(hostMessage, &msg)) {
309 success = requestTimer(msg->enable(), TimerType::WAKEUP,
310 Nanoseconds(msg->wakeup_interval_ns()));
311 }
312 break;
313 }
314 case MessageType::WIFI_SCAN_TEST: {
315 const WifiScanMessage *msg;
316 if (verifyMessage<WifiScanMessage>(hostMessage, &msg)) {
317 mWifiScanType = static_cast<uint8_t>(msg->scan_type());
318 mWifiRadioChain = static_cast<uint8_t>(msg->radio_chain());
319 mWifiChannelSet = static_cast<uint8_t>(msg->channel_set());
320 success = requestTimer(msg->enable(), TimerType::WIFI,
321 Nanoseconds(msg->scan_interval_ns()));
322 }
323 break;
324 }
325 case MessageType::GNSS_LOCATION_TEST: {
326 const GnssLocationMessage *msg;
327 if (verifyMessage<GnssLocationMessage>(hostMessage, &msg)) {
328 success =
329 requestGnssLocation(msg->enable(), msg->scan_interval_millis(),
330 msg->min_time_to_next_fix_millis());
331 }
332 break;
333 }
334 case MessageType::CELL_QUERY_TEST: {
335 const CellQueryMessage *msg;
336 if (verifyMessage<CellQueryMessage>(hostMessage, &msg)) {
337 success = requestTimer(msg->enable(), TimerType::CELL,
338 Nanoseconds(msg->query_interval_ns()));
339 }
340 break;
341 }
342 case MessageType::AUDIO_REQUEST_TEST: {
343 const AudioRequestMessage *msg;
344 if (verifyMessage<AudioRequestMessage>(hostMessage, &msg)) {
345 success = requestAudio(msg->enable(), msg->buffer_duration_ns());
346 }
347 break;
348 }
349 case MessageType::SENSOR_REQUEST_TEST: {
350 const SensorRequestMessage *msg;
351 if (verifyMessage<SensorRequestMessage>(hostMessage, &msg)) {
352 success =
353 requestSensor(msg->enable(), static_cast<uint8_t>(msg->sensor()),
354 msg->sampling_interval_ns(), msg->latency_ns());
355 }
356 break;
357 }
358 case MessageType::BREAK_IT_TEST: {
359 const BreakItMessage *msg;
360 if (verifyMessage<BreakItMessage>(hostMessage, &msg)) {
361 success = requestBreakIt(msg->enable());
362 }
363 break;
364 }
365 case MessageType::GNSS_MEASUREMENT_TEST: {
366 const GnssMeasurementMessage *msg;
367 if (verifyMessage<GnssMeasurementMessage>(hostMessage, &msg)) {
368 success =
369 requestGnssMeasurement(msg->enable(), msg->min_interval_millis());
370 }
371 break;
372 }
373 default:
374 LOGE("Received unknown host message %" PRIu32, hostMessage.messageType);
375 }
376 }
377 return success;
378 }
379
380 } // namespace chre
381