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(&params, 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