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