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