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