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