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