1 /*
2 * Copyright (C) 2020 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 "chpp/clients/gnss.h"
18
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <string.h>
24
25 #include "chpp/app.h"
26 #include "chpp/clients.h"
27 #include "chpp/clients/discovery.h"
28 #include "chpp/common/gnss.h"
29 #include "chpp/common/gnss_types.h"
30 #include "chpp/common/standard_uuids.h"
31 #include "chpp/log.h"
32 #include "chpp/macros.h"
33 #include "chpp/memory.h"
34 #include "chre/pal/gnss.h"
35 #include "chre_api/chre/gnss.h"
36
37 #ifndef CHPP_GNSS_DISCOVERY_TIMEOUT_MS
38 #define CHPP_GNSS_DISCOVERY_TIMEOUT_MS CHPP_DISCOVERY_DEFAULT_TIMEOUT_MS
39 #endif
40
41 /************************************************
42 * Prototypes
43 ***********************************************/
44
45 static enum ChppAppErrorCode chppDispatchGnssResponse(void *clientContext,
46 uint8_t *buf, size_t len);
47 static enum ChppAppErrorCode chppDispatchGnssNotification(void *clientContext,
48 uint8_t *buf,
49 size_t len);
50 static bool chppGnssClientInit(void *clientContext, uint8_t handle,
51 struct ChppVersion serviceVersion);
52 static void chppGnssClientDeinit(void *clientContext);
53 static void chppGnssClientNotifyReset(void *clientContext);
54 static void chppGnssClientNotifyMatch(void *clientContext);
55
56 /************************************************
57 * Private Definitions
58 ***********************************************/
59
60 /**
61 * Structure to maintain state for the GNSS client and its Request/Response
62 * (RR) functionality.
63 */
64 struct ChppGnssClientState {
65 struct ChppClientState client; // GNSS client state
66 const struct chrePalGnssApi *api; // GNSS PAL API
67
68 struct ChppRequestResponseState rRState[CHPP_GNSS_CLIENT_REQUEST_MAX + 1];
69
70 uint32_t capabilities; // Cached GetCapabilities result
71 bool requestStateResyncPending; // requestStateResync() is waiting to be
72 // processed
73 };
74
75 // Note: This global definition of gGnssClientContext supports only one
76 // instance of the CHPP GNSS client at a time.
77 struct ChppGnssClientState gGnssClientContext;
78 static const struct chrePalSystemApi *gSystemApi;
79 static const struct chrePalGnssCallbacks *gCallbacks;
80
81 /**
82 * Configuration parameters for this client
83 */
84 static const struct ChppClient kGnssClientConfig = {
85 .descriptor.uuid = CHPP_UUID_GNSS_STANDARD,
86
87 // Version
88 .descriptor.version.major = 1,
89 .descriptor.version.minor = 0,
90 .descriptor.version.patch = 0,
91
92 // Notifies client if CHPP is reset
93 .resetNotifierFunctionPtr = &chppGnssClientNotifyReset,
94
95 // Notifies client if they are matched to a service
96 .matchNotifierFunctionPtr = &chppGnssClientNotifyMatch,
97
98 // Service response dispatch function pointer
99 .responseDispatchFunctionPtr = &chppDispatchGnssResponse,
100
101 // Service notification dispatch function pointer
102 .notificationDispatchFunctionPtr = &chppDispatchGnssNotification,
103
104 // Service response dispatch function pointer
105 .initFunctionPtr = &chppGnssClientInit,
106
107 // Service notification dispatch function pointer
108 .deinitFunctionPtr = &chppGnssClientDeinit,
109
110 // Number of request-response states in the rRStates array.
111 .rRStateCount = ARRAY_SIZE(gGnssClientContext.rRState),
112
113 // Min length is the entire header
114 .minLength = sizeof(struct ChppAppHeader),
115 };
116
117 /************************************************
118 * Prototypes
119 ***********************************************/
120
121 static bool chppGnssClientOpen(const struct chrePalSystemApi *systemApi,
122 const struct chrePalGnssCallbacks *callbacks);
123 static void chppGnssClientClose(void);
124 static uint32_t chppGnssClientGetCapabilities(void);
125 static bool chppGnssClientControlLocationSession(bool enable,
126 uint32_t minIntervalMs,
127 uint32_t minTimeToNextFixMs);
128 static void chppGnssClientReleaseLocationEvent(
129 struct chreGnssLocationEvent *event);
130 static bool chppGnssClientControlMeasurementSession(bool enable,
131 uint32_t minIntervalMs);
132 static void chppGnssClientReleaseMeasurementDataEvent(
133 struct chreGnssDataEvent *event);
134 static bool chppGnssClientConfigurePassiveLocationListener(bool enable);
135
136 static void chppGnssCloseResult(struct ChppGnssClientState *clientContext,
137 uint8_t *buf, size_t len);
138 static void chppGnssGetCapabilitiesResult(
139 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len);
140 static void chppGnssControlLocationSessionResult(
141 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len);
142 static void chppGnssControlMeasurementSessionResult(
143 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len);
144 static void chppGnssConfigurePassiveLocationListenerResult(
145 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len);
146
147 static void chppGnssStateResyncNotification(
148 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len);
149 static void chppGnssLocationResultNotification(
150 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len);
151 static void chppGnssMeasurementResultNotification(
152 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len);
153
154 /************************************************
155 * Private Functions
156 ***********************************************/
157
158 /**
159 * Dispatches a service response from the transport layer that is determined to
160 * be for the GNSS client.
161 *
162 * This function is called from the app layer using its function pointer given
163 * during client registration.
164 *
165 * @param clientContext Maintains status for each client instance.
166 * @param buf Input data. Cannot be null.
167 * @param len Length of input data in bytes.
168 *
169 * @return Indicates the result of this function call.
170 */
chppDispatchGnssResponse(void * clientContext,uint8_t * buf,size_t len)171 static enum ChppAppErrorCode chppDispatchGnssResponse(void *clientContext,
172 uint8_t *buf,
173 size_t len) {
174 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
175 struct ChppGnssClientState *gnssClientContext =
176 (struct ChppGnssClientState *)clientContext;
177 enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
178
179 if (rxHeader->command > CHPP_GNSS_CLIENT_REQUEST_MAX) {
180 error = CHPP_APP_ERROR_INVALID_COMMAND;
181
182 } else if (!chppClientTimestampResponse(
183 &gnssClientContext->client,
184 &gnssClientContext->rRState[rxHeader->command], rxHeader)) {
185 error = CHPP_APP_ERROR_UNEXPECTED_RESPONSE;
186
187 } else {
188 switch (rxHeader->command) {
189 case CHPP_GNSS_OPEN: {
190 chppClientProcessOpenResponse(&gnssClientContext->client, buf, len);
191 if (gnssClientContext->requestStateResyncPending) {
192 gCallbacks->requestStateResync();
193 gnssClientContext->requestStateResyncPending = false;
194 }
195 break;
196 }
197
198 case CHPP_GNSS_CLOSE: {
199 chppGnssCloseResult(gnssClientContext, buf, len);
200 break;
201 }
202
203 case CHPP_GNSS_GET_CAPABILITIES: {
204 chppGnssGetCapabilitiesResult(gnssClientContext, buf, len);
205 break;
206 }
207
208 case CHPP_GNSS_CONTROL_LOCATION_SESSION: {
209 chppGnssControlLocationSessionResult(gnssClientContext, buf, len);
210 break;
211 }
212
213 case CHPP_GNSS_CONTROL_MEASUREMENT_SESSION: {
214 chppGnssControlMeasurementSessionResult(gnssClientContext, buf, len);
215 break;
216 }
217
218 case CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER: {
219 chppGnssConfigurePassiveLocationListenerResult(gnssClientContext, buf,
220 len);
221 break;
222 }
223
224 default: {
225 error = CHPP_APP_ERROR_INVALID_COMMAND;
226 break;
227 }
228 }
229 }
230
231 return error;
232 }
233
234 /**
235 * Dispatches a service notification from the transport layer that is determined
236 * to be for the GNSS client.
237 *
238 * This function is called from the app layer using its function pointer given
239 * during client registration.
240 *
241 * @param clientContext Maintains status for each client instance.
242 * @param buf Input data. Cannot be null.
243 * @param len Length of input data in bytes.
244 *
245 * @return Indicates the result of this function call.
246 */
chppDispatchGnssNotification(void * clientContext,uint8_t * buf,size_t len)247 static enum ChppAppErrorCode chppDispatchGnssNotification(void *clientContext,
248 uint8_t *buf,
249 size_t len) {
250 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
251 struct ChppGnssClientState *gnssClientContext =
252 (struct ChppGnssClientState *)clientContext;
253 enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
254
255 switch (rxHeader->command) {
256 case CHPP_GNSS_REQUEST_STATE_RESYNC_NOTIFICATION: {
257 chppGnssStateResyncNotification(gnssClientContext, buf, len);
258 break;
259 }
260
261 case CHPP_GNSS_LOCATION_RESULT_NOTIFICATION: {
262 chppGnssLocationResultNotification(gnssClientContext, buf, len);
263 break;
264 }
265
266 case CHPP_GNSS_MEASUREMENT_RESULT_NOTIFICATION: {
267 chppGnssMeasurementResultNotification(gnssClientContext, buf, len);
268 break;
269 }
270
271 default: {
272 error = CHPP_APP_ERROR_INVALID_COMMAND;
273 break;
274 }
275 }
276
277 return error;
278 }
279
280 /**
281 * Initializes the client and provides its handle number and the version of the
282 * matched service when/if it the client is matched with a service during
283 * discovery.
284 *
285 * @param clientContext Maintains status for each client instance.
286 * @param handle Handle number for this client.
287 * @param serviceVersion Version of the matched service.
288 *
289 * @return True if client is compatible and successfully initialized.
290 */
chppGnssClientInit(void * clientContext,uint8_t handle,struct ChppVersion serviceVersion)291 static bool chppGnssClientInit(void *clientContext, uint8_t handle,
292 struct ChppVersion serviceVersion) {
293 UNUSED_VAR(serviceVersion);
294
295 struct ChppGnssClientState *gnssClientContext =
296 (struct ChppGnssClientState *)clientContext;
297 chppClientInit(&gnssClientContext->client, handle);
298
299 return true;
300 }
301
302 /**
303 * Deinitializes the client.
304 *
305 * @param clientContext Maintains status for each client instance.
306 */
chppGnssClientDeinit(void * clientContext)307 static void chppGnssClientDeinit(void *clientContext) {
308 struct ChppGnssClientState *gnssClientContext =
309 (struct ChppGnssClientState *)clientContext;
310 chppClientDeinit(&gnssClientContext->client);
311 }
312
313 /**
314 * Notifies the client of an incoming reset.
315 *
316 * @param clientContext Maintains status for each client instance.
317 */
chppGnssClientNotifyReset(void * clientContext)318 static void chppGnssClientNotifyReset(void *clientContext) {
319 struct ChppGnssClientState *gnssClientContext =
320 (struct ChppGnssClientState *)clientContext;
321
322 chppClientCloseOpenRequests(&gnssClientContext->client, &kGnssClientConfig,
323 false /* clearOnly */);
324
325 if (gnssClientContext->client.openState != CHPP_OPEN_STATE_OPENED &&
326 !gnssClientContext->client.pseudoOpen) {
327 CHPP_LOGW("GNSS client reset but wasn't open");
328 } else {
329 CHPP_LOGI("GNSS client reopening from state=%" PRIu8,
330 gnssClientContext->client.openState);
331 gnssClientContext->requestStateResyncPending = true;
332 chppClientSendOpenRequest(&gGnssClientContext.client,
333 &gGnssClientContext.rRState[CHPP_GNSS_OPEN],
334 CHPP_GNSS_OPEN,
335 /*blocking=*/false);
336 }
337 }
338
339 /**
340 * Notifies the client of being matched to a service.
341 *
342 * @param clientContext Maintains status for each client instance.
343 */
chppGnssClientNotifyMatch(void * clientContext)344 static void chppGnssClientNotifyMatch(void *clientContext) {
345 struct ChppGnssClientState *gnssClientContext =
346 (struct ChppGnssClientState *)clientContext;
347
348 if (gnssClientContext->client.pseudoOpen) {
349 CHPP_LOGD("Pseudo-open GNSS client opening");
350 chppClientSendOpenRequest(&gGnssClientContext.client,
351 &gGnssClientContext.rRState[CHPP_GNSS_OPEN],
352 CHPP_GNSS_OPEN,
353 /*blocking=*/false);
354 }
355 }
356
357 /**
358 * Handles the service response for the close client request.
359 *
360 * This function is called from chppDispatchGnssResponse().
361 *
362 * @param clientContext Maintains status for each client instance.
363 * @param buf Input data. Cannot be null.
364 * @param len Length of input data in bytes.
365 */
chppGnssCloseResult(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)366 static void chppGnssCloseResult(struct ChppGnssClientState *clientContext,
367 uint8_t *buf, size_t len) {
368 // TODO
369 UNUSED_VAR(clientContext);
370 UNUSED_VAR(buf);
371 UNUSED_VAR(len);
372 }
373
374 /**
375 * Handles the service response for the get capabilities client request.
376 *
377 * This function is called from chppDispatchGnssResponse().
378 *
379 * @param clientContext Maintains status for each client instance.
380 * @param buf Input data. Cannot be null.
381 * @param len Length of input data in bytes.
382 */
chppGnssGetCapabilitiesResult(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)383 static void chppGnssGetCapabilitiesResult(
384 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) {
385 if (len < sizeof(struct ChppGnssGetCapabilitiesResponse)) {
386 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
387 CHPP_LOGE("GetCapabilities resp. too short. err=%" PRIu8, rxHeader->error);
388
389 } else {
390 struct ChppGnssGetCapabilitiesParameters *result =
391 &((struct ChppGnssGetCapabilitiesResponse *)buf)->params;
392
393 CHPP_LOGD("chppGnssGetCapabilitiesResult received capabilities=0x%" PRIx32,
394 result->capabilities);
395
396 #ifdef CHPP_GNSS_DEFAULT_CAPABILITIES
397 CHPP_ASSERT_LOG((result->capabilities == CHPP_GNSS_DEFAULT_CAPABILITIES),
398 "Unexpected capability 0x%" PRIx32 " != 0x%" PRIx32,
399 result->capabilities, CHPP_GNSS_DEFAULT_CAPABILITIES);
400 #endif
401
402 clientContext->capabilities = result->capabilities;
403 }
404 }
405
406 /**
407 * Handles the service response for the Control Location Session client request.
408 *
409 * This function is called from chppDispatchGnssResponse().
410 *
411 * @param clientContext Maintains status for each client instance.
412 * @param buf Input data. Cannot be null.
413 * @param len Length of input data in bytes.
414 */
chppGnssControlLocationSessionResult(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)415 static void chppGnssControlLocationSessionResult(
416 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) {
417 UNUSED_VAR(clientContext);
418
419 if (len < sizeof(struct ChppGnssControlLocationSessionResponse)) {
420 // Short response length indicates an error
421
422 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
423 CHPP_LOGE("ControlLocation resp. too short. err=%" PRIu8, rxHeader->error);
424
425 if (rxHeader->error == CHPP_APP_ERROR_NONE) {
426 rxHeader->error = CHPP_APP_ERROR_INVALID_LENGTH;
427 }
428 gCallbacks->locationStatusChangeCallback(
429 false, chppAppErrorToChreError(rxHeader->error));
430
431 } else {
432 struct ChppGnssControlLocationSessionResponse *result =
433 (struct ChppGnssControlLocationSessionResponse *)buf;
434
435 CHPP_LOGD(
436 "chppGnssControlLocationSessionResult received enable=%d, "
437 "errorCode=%" PRIu8,
438 result->enabled, result->errorCode);
439
440 gCallbacks->locationStatusChangeCallback(result->enabled,
441 result->errorCode);
442 }
443 }
444
445 /**
446 * Handles the service response for the Control Measurement Session client
447 * request.
448 *
449 * This function is called from chppDispatchGnssResponse().
450 *
451 * @param clientContext Maintains status for each client instance.
452 * @param buf Input data. Cannot be null.
453 * @param len Length of input data in bytes.
454 */
chppGnssControlMeasurementSessionResult(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)455 static void chppGnssControlMeasurementSessionResult(
456 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) {
457 UNUSED_VAR(clientContext);
458
459 if (len < sizeof(struct ChppGnssControlMeasurementSessionResponse)) {
460 // Short response length indicates an error
461
462 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
463 CHPP_LOGE("Measurement resp. too short. err=%" PRIu8, rxHeader->error);
464
465 if (rxHeader->error == CHPP_APP_ERROR_NONE) {
466 rxHeader->error = CHPP_APP_ERROR_INVALID_LENGTH;
467 }
468 gCallbacks->measurementStatusChangeCallback(
469 false, chppAppErrorToChreError(rxHeader->error));
470
471 } else {
472 struct ChppGnssControlMeasurementSessionResponse *result =
473 (struct ChppGnssControlMeasurementSessionResponse *)buf;
474
475 CHPP_LOGD(
476 "chppGnssControlMeasurementSessionResult received enable=%d, "
477 "errorCode=%" PRIu8,
478 result->enabled, result->errorCode);
479
480 gCallbacks->measurementStatusChangeCallback(result->enabled,
481 result->errorCode);
482 }
483 }
484
485 /**
486 * Handles the service response for the Configure Passive Location Listener
487 * client request.
488 *
489 * This function is called from chppDispatchGnssResponse().
490 *
491 * @param clientContext Maintains status for each client instance.
492 * @param buf Input data. Cannot be null.
493 * @param len Length of input data in bytes.
494 */
chppGnssConfigurePassiveLocationListenerResult(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)495 static void chppGnssConfigurePassiveLocationListenerResult(
496 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) {
497 UNUSED_VAR(clientContext);
498 UNUSED_VAR(len);
499
500 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
501
502 if (rxHeader->error != CHPP_APP_ERROR_NONE) {
503 CHPP_LOGE("Passive scan failed at service err=%" PRIu8, rxHeader->error);
504 CHPP_DEBUG_ASSERT(false);
505
506 } else {
507 CHPP_LOGD(
508 "WiFi ConfigurePassiveLocationListener request accepted at service");
509 }
510 }
511
512 /**
513 * Handles the State Resync service notification.
514 *
515 * This function is called from chppDispatchGnssNotification().
516 *
517 * @param clientContext Maintains status for each client instance.
518 * @param buf Input data. Cannot be null.
519 * @param len Length of input data in bytes.
520 */
chppGnssStateResyncNotification(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)521 static void chppGnssStateResyncNotification(
522 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) {
523 UNUSED_VAR(buf);
524 UNUSED_VAR(len);
525 if (clientContext->client.openState == CHPP_OPEN_STATE_WAITING_TO_OPEN) {
526 // If the GNSS client is waiting for the open to proceed, the CHRE handler
527 // for requestStateResync() may fail, so we set a flag to process it later
528 // when the open has succeeded.
529 clientContext->requestStateResyncPending = true;
530 } else {
531 gCallbacks->requestStateResync();
532 clientContext->requestStateResyncPending = false;
533 }
534 }
535
536 /**
537 * Handles the Location Result service notification.
538 *
539 * This function is called from chppDispatchGnssNotification().
540 *
541 * @param clientContext Maintains status for each client instance.
542 * @param buf Input data. Cannot be null.
543 * @param len Length of input data in bytes.
544 */
chppGnssLocationResultNotification(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)545 static void chppGnssLocationResultNotification(
546 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) {
547 UNUSED_VAR(clientContext);
548 CHPP_LOGD("chppGnssLocationResultNotification received data len=%" PRIuSIZE,
549 len);
550
551 buf += sizeof(struct ChppAppHeader);
552 len -= sizeof(struct ChppAppHeader);
553
554 struct chreGnssLocationEvent *chre =
555 chppGnssLocationEventToChre((struct ChppGnssLocationEvent *)buf, len);
556
557 if (chre == NULL) {
558 CHPP_LOGE("Location result conversion failed: len=%" PRIuSIZE, len);
559 } else {
560 gCallbacks->locationEventCallback(chre);
561 }
562 }
563
564 /**
565 * Handles the Measurement Result service notification.
566 *
567 * This function is called from chppDispatchGnssNotification().
568 *
569 * @param clientContext Maintains status for each client instance.
570 * @param buf Input data. Cannot be null.
571 * @param len Length of input data in bytes.
572 */
chppGnssMeasurementResultNotification(struct ChppGnssClientState * clientContext,uint8_t * buf,size_t len)573 static void chppGnssMeasurementResultNotification(
574 struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) {
575 UNUSED_VAR(clientContext);
576 CHPP_LOGD(
577 "chppGnssMeasurementResultNotification received data len=%" PRIuSIZE,
578 len);
579
580 buf += sizeof(struct ChppAppHeader);
581 len -= sizeof(struct ChppAppHeader);
582
583 struct chreGnssDataEvent *chre =
584 chppGnssDataEventToChre((struct ChppGnssDataEvent *)buf, len);
585
586 if (chre == NULL) {
587 CHPP_LOGE("Measurement result conversion failed len=%" PRIuSIZE, len);
588 } else {
589 gCallbacks->measurementEventCallback(chre);
590 }
591 }
592
593 /**
594 * Initializes the GNSS client upon an open request from CHRE and responds
595 * with the result.
596 *
597 * @param systemApi CHRE system function pointers.
598 * @param callbacks CHRE entry points.
599 *
600 * @return True if successful. False otherwise.
601 */
chppGnssClientOpen(const struct chrePalSystemApi * systemApi,const struct chrePalGnssCallbacks * callbacks)602 static bool chppGnssClientOpen(const struct chrePalSystemApi *systemApi,
603 const struct chrePalGnssCallbacks *callbacks) {
604 CHPP_DEBUG_ASSERT(systemApi != NULL);
605 CHPP_DEBUG_ASSERT(callbacks != NULL);
606
607 bool result = false;
608 gSystemApi = systemApi;
609 gCallbacks = callbacks;
610
611 CHPP_LOGD("GNSS client opening");
612
613 if (chppWaitForDiscoveryComplete(gGnssClientContext.client.appContext,
614 CHPP_GNSS_DISCOVERY_TIMEOUT_MS)) {
615 result = chppClientSendOpenRequest(
616 &gGnssClientContext.client, &gGnssClientContext.rRState[CHPP_GNSS_OPEN],
617 CHPP_GNSS_OPEN,
618 /*blocking=*/true);
619 }
620
621 #ifdef CHPP_GNSS_CLIENT_OPEN_ALWAYS_SUCCESS
622 chppClientPseudoOpen(&gGnssClientContext.client);
623 result = true;
624 #endif
625
626 return result;
627 }
628
629 /**
630 * Deinitializes the GNSS client.
631 */
chppGnssClientClose(void)632 static void chppGnssClientClose(void) {
633 // Remote
634 struct ChppAppHeader *request = chppAllocClientRequestCommand(
635 &gGnssClientContext.client, CHPP_GNSS_CLOSE);
636
637 if (request == NULL) {
638 CHPP_LOG_OOM();
639 } else if (chppSendTimestampedRequestAndWait(
640 &gGnssClientContext.client,
641 &gGnssClientContext.rRState[CHPP_GNSS_CLOSE], request,
642 sizeof(*request))) {
643 gGnssClientContext.client.openState = CHPP_OPEN_STATE_CLOSED;
644 gGnssClientContext.capabilities = CHRE_GNSS_CAPABILITIES_NONE;
645 chppClientCloseOpenRequests(&gGnssClientContext.client, &kGnssClientConfig,
646 true /* clearOnly */);
647 }
648 }
649
650 /**
651 * Retrieves a set of flags indicating the GNSS features supported by the
652 * current implementation.
653 *
654 * @return Capabilities flags.
655 */
chppGnssClientGetCapabilities(void)656 static uint32_t chppGnssClientGetCapabilities(void) {
657 #ifdef CHPP_GNSS_DEFAULT_CAPABILITIES
658 uint32_t capabilities = CHPP_GNSS_DEFAULT_CAPABILITIES;
659 #else
660 uint32_t capabilities = CHRE_GNSS_CAPABILITIES_NONE;
661 #endif
662
663 if (gGnssClientContext.capabilities != CHRE_GNSS_CAPABILITIES_NONE) {
664 // Result already cached
665 capabilities = gGnssClientContext.capabilities;
666
667 } else {
668 struct ChppAppHeader *request = chppAllocClientRequestCommand(
669 &gGnssClientContext.client, CHPP_GNSS_GET_CAPABILITIES);
670
671 if (request == NULL) {
672 CHPP_LOG_OOM();
673 } else {
674 if (chppSendTimestampedRequestAndWait(
675 &gGnssClientContext.client,
676 &gGnssClientContext.rRState[CHPP_GNSS_GET_CAPABILITIES], request,
677 sizeof(*request))) {
678 // Success. gGnssClientContext.capabilities is now populated
679 capabilities = gGnssClientContext.capabilities;
680 }
681 }
682 }
683
684 return capabilities;
685 }
686
687 /**
688 * Start/stop/modify the GNSS location session used for clients of the CHRE
689 * API.
690 *
691 * @param enable true to start/modify the session, false to stop the
692 * session. If false, other parameters are ignored.
693 * @param minIntervalMs See chreGnssLocationSessionStartAsync()
694 * @param minTimeToNextFixMs See chreGnssLocationSessionStartAsync()
695 *
696 * @return True indicates the request was sent off to the service.
697 */
698
chppGnssClientControlLocationSession(bool enable,uint32_t minIntervalMs,uint32_t minTimeToNextFixMs)699 static bool chppGnssClientControlLocationSession(bool enable,
700 uint32_t minIntervalMs,
701 uint32_t minTimeToNextFixMs) {
702 bool result = false;
703
704 struct ChppGnssControlLocationSessionRequest *request =
705 chppAllocClientRequestFixed(&gGnssClientContext.client,
706 struct ChppGnssControlLocationSessionRequest);
707
708 if (request == NULL) {
709 CHPP_LOG_OOM();
710 } else {
711 request->header.command = CHPP_GNSS_CONTROL_LOCATION_SESSION;
712 request->params.enable = enable;
713 request->params.minIntervalMs = minIntervalMs;
714 request->params.minTimeToNextFixMs = minTimeToNextFixMs;
715
716 result = chppSendTimestampedRequestOrFail(
717 &gGnssClientContext.client,
718 &gGnssClientContext.rRState[CHPP_GNSS_CONTROL_LOCATION_SESSION],
719 request, sizeof(*request), CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS);
720 }
721
722 return result;
723 }
724
725 /**
726 * Releases the memory held for the location event callback.
727 *
728 * @param event Location event to be released.
729 */
chppGnssClientReleaseLocationEvent(struct chreGnssLocationEvent * event)730 static void chppGnssClientReleaseLocationEvent(
731 struct chreGnssLocationEvent *event) {
732 CHPP_FREE_AND_NULLIFY(event);
733 }
734
735 /**
736 * Start/stop/modify the raw GNSS measurement session used for clients of the
737 * CHRE API.
738 *
739 * @param enable true to start/modify the session, false to stop the
740 * session. If false, other parameters are ignored.
741 * @param minIntervalMs See chreGnssMeasurementSessionStartAsync()
742 *
743 * @return True indicates the request was sent off to the service.
744 */
745
chppGnssClientControlMeasurementSession(bool enable,uint32_t minIntervalMs)746 static bool chppGnssClientControlMeasurementSession(bool enable,
747 uint32_t minIntervalMs) {
748 bool result = false;
749
750 struct ChppGnssControlMeasurementSessionRequest *request =
751 chppAllocClientRequestFixed(
752 &gGnssClientContext.client,
753 struct ChppGnssControlMeasurementSessionRequest);
754
755 if (request == NULL) {
756 CHPP_LOG_OOM();
757 } else {
758 request->header.command = CHPP_GNSS_CONTROL_MEASUREMENT_SESSION;
759 request->params.enable = enable;
760 request->params.minIntervalMs = minIntervalMs;
761
762 result = chppSendTimestampedRequestOrFail(
763 &gGnssClientContext.client,
764 &gGnssClientContext.rRState[CHPP_GNSS_CONTROL_MEASUREMENT_SESSION],
765 request, sizeof(*request), CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS);
766 }
767
768 return result;
769 }
770
771 /**
772 * Releases the memory held for the measurement event callback.
773 *
774 * @param event Measurement event to be released.
775 */
chppGnssClientReleaseMeasurementDataEvent(struct chreGnssDataEvent * event)776 static void chppGnssClientReleaseMeasurementDataEvent(
777 struct chreGnssDataEvent *event) {
778 if (event->measurement_count > 0) {
779 void *measurements = CHPP_CONST_CAST_POINTER(event->measurements);
780 CHPP_FREE_AND_NULLIFY(measurements);
781 }
782
783 CHPP_FREE_AND_NULLIFY(event);
784 }
785
786 /**
787 * Starts/stops opportunistic delivery of location fixes.
788 *
789 * @param enable true to turn the passive location listener on, false to
790 * turn it off.
791 *
792 * @return True indicates the request was sent off to the service.
793 */
chppGnssClientConfigurePassiveLocationListener(bool enable)794 static bool chppGnssClientConfigurePassiveLocationListener(bool enable) {
795 bool result = false;
796
797 struct ChppGnssConfigurePassiveLocationListenerRequest *request =
798 chppAllocClientRequestFixed(
799 &gGnssClientContext.client,
800 struct ChppGnssConfigurePassiveLocationListenerRequest);
801
802 if (request == NULL) {
803 CHPP_LOG_OOM();
804 } else {
805 request->header.command = CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER;
806 request->params.enable = enable;
807
808 result = chppSendTimestampedRequestOrFail(
809 &gGnssClientContext.client,
810 &gGnssClientContext
811 .rRState[CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER],
812 request, sizeof(*request), CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT);
813 }
814
815 return result;
816 }
817
818 /************************************************
819 * Public Functions
820 ***********************************************/
821
chppRegisterGnssClient(struct ChppAppState * appContext)822 void chppRegisterGnssClient(struct ChppAppState *appContext) {
823 chppRegisterClient(appContext, (void *)&gGnssClientContext,
824 &gGnssClientContext.client, gGnssClientContext.rRState,
825 &kGnssClientConfig);
826 }
827
chppDeregisterGnssClient(struct ChppAppState * appContext)828 void chppDeregisterGnssClient(struct ChppAppState *appContext) {
829 // TODO
830
831 UNUSED_VAR(appContext);
832 }
833
getChppGnssClientState(void)834 struct ChppClientState *getChppGnssClientState(void) {
835 return &gGnssClientContext.client;
836 }
837
838 #ifdef CHPP_CLIENT_ENABLED_GNSS
839
840 #ifdef CHPP_CLIENT_ENABLED_CHRE_GNSS
chrePalGnssGetApi(uint32_t requestedApiVersion)841 const struct chrePalGnssApi *chrePalGnssGetApi(uint32_t requestedApiVersion) {
842 #else
843 const struct chrePalGnssApi *chppPalGnssGetApi(uint32_t requestedApiVersion) {
844 #endif
845
846 static const struct chrePalGnssApi api = {
847 .moduleVersion = CHPP_PAL_GNSS_API_VERSION,
848 .open = chppGnssClientOpen,
849 .close = chppGnssClientClose,
850 .getCapabilities = chppGnssClientGetCapabilities,
851 .controlLocationSession = chppGnssClientControlLocationSession,
852 .releaseLocationEvent = chppGnssClientReleaseLocationEvent,
853 .controlMeasurementSession = chppGnssClientControlMeasurementSession,
854 .releaseMeasurementDataEvent = chppGnssClientReleaseMeasurementDataEvent,
855 .configurePassiveLocationListener =
856 chppGnssClientConfigurePassiveLocationListener,
857 };
858
859 CHPP_STATIC_ASSERT(
860 CHRE_PAL_GNSS_API_CURRENT_VERSION == CHPP_PAL_GNSS_API_VERSION,
861 "A newer CHRE PAL API version is available. Please update.");
862
863 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(api.moduleVersion,
864 requestedApiVersion)) {
865 return NULL;
866 } else {
867 return &api;
868 }
869 }
870
871 #endif
872