| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "chpp/clients/gnss.h" |
| |
| #include <inttypes.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <string.h> |
| |
| #include "chpp/app.h" |
| #include "chpp/clients.h" |
| #include "chpp/clients/discovery.h" |
| #include "chpp/common/gnss.h" |
| #include "chpp/common/gnss_types.h" |
| #include "chpp/common/standard_uuids.h" |
| #include "chpp/log.h" |
| #include "chpp/macros.h" |
| #include "chpp/memory.h" |
| #include "chre/pal/gnss.h" |
| #include "chre_api/chre/gnss.h" |
| |
| #ifndef CHPP_GNSS_DISCOVERY_TIMEOUT_MS |
| #define CHPP_GNSS_DISCOVERY_TIMEOUT_MS CHPP_DISCOVERY_DEFAULT_TIMEOUT_MS |
| #endif |
| |
| /************************************************ |
| * Prototypes |
| ***********************************************/ |
| |
| static enum ChppAppErrorCode chppDispatchGnssResponse(void *clientContext, |
| uint8_t *buf, size_t len); |
| static enum ChppAppErrorCode chppDispatchGnssNotification(void *clientContext, |
| uint8_t *buf, |
| size_t len); |
| static bool chppGnssClientInit(void *clientContext, uint8_t handle, |
| struct ChppVersion serviceVersion); |
| static void chppGnssClientDeinit(void *clientContext); |
| static void chppGnssClientNotifyReset(void *clientContext); |
| static void chppGnssClientNotifyMatch(void *clientContext); |
| |
| /************************************************ |
| * Private Definitions |
| ***********************************************/ |
| |
| /** |
| * Structure to maintain state for the GNSS client and its Request/Response |
| * (RR) functionality. |
| */ |
| struct ChppGnssClientState { |
| struct ChppEndpointState client; // CHPP client state |
| const struct chrePalGnssApi *api; // GNSS PAL API |
| |
| struct ChppOutgoingRequestState |
| outReqStates[CHPP_GNSS_CLIENT_REQUEST_MAX + 1]; |
| |
| uint32_t capabilities; // Cached GetCapabilities result |
| bool requestStateResyncPending; // requestStateResync() is waiting to be |
| // processed |
| bool capabilitiesValid; // Flag to indicate if the capabilities result |
| // is valid |
| }; |
| |
| // Note: This global definition of gGnssClientContext supports only one |
| // instance of the CHPP GNSS client at a time. |
| struct ChppGnssClientState gGnssClientContext; |
| static const struct chrePalSystemApi *gSystemApi; |
| static const struct chrePalGnssCallbacks *gCallbacks; |
| |
| /** |
| * Configuration parameters for this client |
| */ |
| static const struct ChppClient kGnssClientConfig = { |
| .descriptor.uuid = CHPP_UUID_GNSS_STANDARD, |
| |
| // Version |
| .descriptor.version.major = 1, |
| .descriptor.version.minor = 0, |
| .descriptor.version.patch = 0, |
| |
| // Notifies client if CHPP is reset |
| .resetNotifierFunctionPtr = &chppGnssClientNotifyReset, |
| |
| // Notifies client if they are matched to a service |
| .matchNotifierFunctionPtr = &chppGnssClientNotifyMatch, |
| |
| // Service response dispatch function pointer |
| .responseDispatchFunctionPtr = &chppDispatchGnssResponse, |
| |
| // Service notification dispatch function pointer |
| .notificationDispatchFunctionPtr = &chppDispatchGnssNotification, |
| |
| // Service response dispatch function pointer |
| .initFunctionPtr = &chppGnssClientInit, |
| |
| // Service notification dispatch function pointer |
| .deinitFunctionPtr = &chppGnssClientDeinit, |
| |
| // Number of request-response states in the outReqStates array. |
| .outReqCount = ARRAY_SIZE(gGnssClientContext.outReqStates), |
| |
| // Min length is the entire header |
| .minLength = sizeof(struct ChppAppHeader), |
| }; |
| |
| /************************************************ |
| * Prototypes |
| ***********************************************/ |
| |
| static bool chppGnssClientOpen(const struct chrePalSystemApi *systemApi, |
| const struct chrePalGnssCallbacks *callbacks); |
| static void chppGnssClientClose(void); |
| static uint32_t chppGnssClientGetCapabilities(void); |
| static bool chppGnssClientControlLocationSession(bool enable, |
| uint32_t minIntervalMs, |
| uint32_t minTimeToNextFixMs); |
| static void chppGnssClientReleaseLocationEvent( |
| struct chreGnssLocationEvent *event); |
| static bool chppGnssClientControlMeasurementSession(bool enable, |
| uint32_t minIntervalMs); |
| static void chppGnssClientReleaseMeasurementDataEvent( |
| struct chreGnssDataEvent *event); |
| static bool chppGnssClientConfigurePassiveLocationListener(bool enable); |
| |
| static void chppGnssCloseResult(struct ChppGnssClientState *clientContext, |
| uint8_t *buf, size_t len); |
| static void chppGnssGetCapabilitiesResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len); |
| static void chppGnssControlLocationSessionResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len); |
| static void chppGnssControlMeasurementSessionResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len); |
| static void chppGnssConfigurePassiveLocationListenerResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len); |
| |
| static void chppGnssStateResyncNotification( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len); |
| static void chppGnssLocationResultNotification( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len); |
| static void chppGnssMeasurementResultNotification( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len); |
| |
| /************************************************ |
| * Private Functions |
| ***********************************************/ |
| |
| /** |
| * Dispatches a service response from the transport layer that is determined to |
| * be for the GNSS client. |
| * |
| * This function is called from the app layer using its function pointer given |
| * during client registration. |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| * |
| * @return Indicates the result of this function call. |
| */ |
| static enum ChppAppErrorCode chppDispatchGnssResponse(void *clientContext, |
| uint8_t *buf, |
| size_t len) { |
| struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf; |
| struct ChppGnssClientState *gnssClientContext = |
| (struct ChppGnssClientState *)clientContext; |
| enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; |
| |
| if (rxHeader->command > CHPP_GNSS_CLIENT_REQUEST_MAX) { |
| error = CHPP_APP_ERROR_INVALID_COMMAND; |
| |
| } else if (!chppTimestampIncomingResponse( |
| gnssClientContext->client.appContext, |
| &gnssClientContext->outReqStates[rxHeader->command], |
| rxHeader)) { |
| error = CHPP_APP_ERROR_UNEXPECTED_RESPONSE; |
| |
| } else { |
| switch (rxHeader->command) { |
| case CHPP_GNSS_OPEN: { |
| chppClientProcessOpenResponse(&gnssClientContext->client, buf, len); |
| if (rxHeader->error == CHPP_APP_ERROR_NONE && |
| gnssClientContext->requestStateResyncPending) { |
| gCallbacks->requestStateResync(); |
| gnssClientContext->requestStateResyncPending = false; |
| } |
| break; |
| } |
| |
| case CHPP_GNSS_CLOSE: { |
| chppGnssCloseResult(gnssClientContext, buf, len); |
| break; |
| } |
| |
| case CHPP_GNSS_GET_CAPABILITIES: { |
| chppGnssGetCapabilitiesResult(gnssClientContext, buf, len); |
| break; |
| } |
| |
| case CHPP_GNSS_CONTROL_LOCATION_SESSION: { |
| chppGnssControlLocationSessionResult(gnssClientContext, buf, len); |
| break; |
| } |
| |
| case CHPP_GNSS_CONTROL_MEASUREMENT_SESSION: { |
| chppGnssControlMeasurementSessionResult(gnssClientContext, buf, len); |
| break; |
| } |
| |
| case CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER: { |
| chppGnssConfigurePassiveLocationListenerResult(gnssClientContext, buf, |
| len); |
| break; |
| } |
| |
| default: { |
| error = CHPP_APP_ERROR_INVALID_COMMAND; |
| break; |
| } |
| } |
| } |
| |
| return error; |
| } |
| |
| /** |
| * Dispatches a service notification from the transport layer that is determined |
| * to be for the GNSS client. |
| * |
| * This function is called from the app layer using its function pointer given |
| * during client registration. |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| * |
| * @return Indicates the result of this function call. |
| */ |
| static enum ChppAppErrorCode chppDispatchGnssNotification(void *clientContext, |
| uint8_t *buf, |
| size_t len) { |
| struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf; |
| struct ChppGnssClientState *gnssClientContext = |
| (struct ChppGnssClientState *)clientContext; |
| enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; |
| |
| switch (rxHeader->command) { |
| case CHPP_GNSS_REQUEST_STATE_RESYNC_NOTIFICATION: { |
| chppGnssStateResyncNotification(gnssClientContext, buf, len); |
| break; |
| } |
| |
| case CHPP_GNSS_LOCATION_RESULT_NOTIFICATION: { |
| chppGnssLocationResultNotification(gnssClientContext, buf, len); |
| break; |
| } |
| |
| case CHPP_GNSS_MEASUREMENT_RESULT_NOTIFICATION: { |
| chppGnssMeasurementResultNotification(gnssClientContext, buf, len); |
| break; |
| } |
| |
| default: { |
| error = CHPP_APP_ERROR_INVALID_COMMAND; |
| break; |
| } |
| } |
| |
| return error; |
| } |
| |
| /** |
| * Initializes the client and provides its handle number and the version of the |
| * matched service when/if it the client is matched with a service during |
| * discovery. |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param handle Handle number for this client. |
| * @param serviceVersion Version of the matched service. |
| * |
| * @return True if client is compatible and successfully initialized. |
| */ |
| static bool chppGnssClientInit(void *clientContext, uint8_t handle, |
| struct ChppVersion serviceVersion) { |
| UNUSED_VAR(serviceVersion); |
| |
| struct ChppGnssClientState *gnssClientContext = |
| (struct ChppGnssClientState *)clientContext; |
| chppClientInit(&gnssClientContext->client, handle); |
| |
| return true; |
| } |
| |
| /** |
| * Deinitializes the client. |
| * |
| * @param clientContext Maintains status for each client instance. |
| */ |
| static void chppGnssClientDeinit(void *clientContext) { |
| struct ChppGnssClientState *gnssClientContext = |
| (struct ChppGnssClientState *)clientContext; |
| chppClientDeinit(&gnssClientContext->client); |
| } |
| |
| /** |
| * Notifies the client of an incoming reset. |
| * |
| * @param clientContext Maintains status for each client instance. |
| */ |
| static void chppGnssClientNotifyReset(void *clientContext) { |
| struct ChppGnssClientState *gnssClientContext = |
| (struct ChppGnssClientState *)clientContext; |
| |
| chppClientCloseOpenRequests(&gnssClientContext->client, &kGnssClientConfig, |
| false /* clearOnly */); |
| |
| CHPP_LOGD("GNSS client reopening from state=%" PRIu8, |
| gnssClientContext->client.openState); |
| gnssClientContext->requestStateResyncPending = true; |
| chppClientSendOpenRequest(&gGnssClientContext.client, |
| &gGnssClientContext.outReqStates[CHPP_GNSS_OPEN], |
| CHPP_GNSS_OPEN, |
| /*blocking=*/false); |
| } |
| |
| /** |
| * Notifies the client of being matched to a service. |
| * |
| * @param clientContext Maintains status for each client instance. |
| */ |
| static void chppGnssClientNotifyMatch(void *clientContext) { |
| struct ChppGnssClientState *gnssClientContext = |
| (struct ChppGnssClientState *)clientContext; |
| |
| if (gnssClientContext->client.pseudoOpen) { |
| CHPP_LOGD("Pseudo-open GNSS client opening"); |
| chppClientSendOpenRequest(&gGnssClientContext.client, |
| &gGnssClientContext.outReqStates[CHPP_GNSS_OPEN], |
| CHPP_GNSS_OPEN, |
| /*blocking=*/false); |
| } |
| } |
| |
| /** |
| * Handles the service response for the close client request. |
| * |
| * This function is called from chppDispatchGnssResponse(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssCloseResult(struct ChppGnssClientState *clientContext, |
| uint8_t *buf, size_t len) { |
| // TODO |
| UNUSED_VAR(clientContext); |
| UNUSED_VAR(buf); |
| UNUSED_VAR(len); |
| } |
| |
| /** |
| * Handles the service response for the get capabilities client request. |
| * |
| * This function is called from chppDispatchGnssResponse(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssGetCapabilitiesResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) { |
| if (len < sizeof(struct ChppGnssGetCapabilitiesResponse)) { |
| CHPP_LOGE("Bad GNSS capabilities len=%" PRIuSIZE, len); |
| |
| } else { |
| struct ChppGnssGetCapabilitiesParameters *result = |
| &((struct ChppGnssGetCapabilitiesResponse *)buf)->params; |
| |
| CHPP_LOGD("chppGnssGetCapabilitiesResult received capabilities=0x%" PRIx32, |
| result->capabilities); |
| |
| CHPP_ASSERT((result->capabilities & CHPP_GNSS_DEFAULT_CAPABILITIES) == |
| CHPP_GNSS_DEFAULT_CAPABILITIES); |
| if (result->capabilities != CHPP_GNSS_DEFAULT_CAPABILITIES) { |
| CHPP_LOGE("GNSS capabilities 0x%" PRIx32 " != 0x%" PRIx32, |
| result->capabilities, (uint32_t)CHPP_GNSS_DEFAULT_CAPABILITIES); |
| } |
| |
| clientContext->capabilitiesValid = true; |
| clientContext->capabilities = result->capabilities; |
| } |
| } |
| |
| /** |
| * Handles the service response for the Control Location Session client request. |
| * |
| * This function is called from chppDispatchGnssResponse(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssControlLocationSessionResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) { |
| UNUSED_VAR(clientContext); |
| |
| if (len < sizeof(struct ChppGnssControlLocationSessionResponse)) { |
| // Short response length indicates an error |
| gCallbacks->locationStatusChangeCallback( |
| false, chppAppShortResponseErrorHandler(buf, len, "ControlLocation")); |
| |
| } else { |
| struct ChppGnssControlLocationSessionResponse *result = |
| (struct ChppGnssControlLocationSessionResponse *)buf; |
| |
| CHPP_LOGD( |
| "chppGnssControlLocationSessionResult received enable=%d, " |
| "errorCode=%" PRIu8, |
| result->enabled, result->errorCode); |
| |
| gCallbacks->locationStatusChangeCallback(result->enabled, |
| result->errorCode); |
| } |
| } |
| |
| /** |
| * Handles the service response for the Control Measurement Session client |
| * request. |
| * |
| * This function is called from chppDispatchGnssResponse(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssControlMeasurementSessionResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) { |
| UNUSED_VAR(clientContext); |
| |
| if (len < sizeof(struct ChppGnssControlMeasurementSessionResponse)) { |
| // Short response length indicates an error |
| gCallbacks->measurementStatusChangeCallback( |
| false, chppAppShortResponseErrorHandler(buf, len, "Measurement")); |
| |
| } else { |
| struct ChppGnssControlMeasurementSessionResponse *result = |
| (struct ChppGnssControlMeasurementSessionResponse *)buf; |
| |
| CHPP_LOGD( |
| "chppGnssControlMeasurementSessionResult received enable=%d, " |
| "errorCode=%" PRIu8, |
| result->enabled, result->errorCode); |
| |
| gCallbacks->measurementStatusChangeCallback(result->enabled, |
| result->errorCode); |
| } |
| } |
| |
| /** |
| * Handles the service response for the Configure Passive Location Listener |
| * client request. |
| * |
| * This function is called from chppDispatchGnssResponse(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssConfigurePassiveLocationListenerResult( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) { |
| UNUSED_VAR(clientContext); |
| UNUSED_VAR(len); |
| |
| struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf; |
| |
| if (rxHeader->error != CHPP_APP_ERROR_NONE) { |
| CHPP_DEBUG_ASSERT_LOG(false, "Passive scan failed at service"); |
| |
| } else { |
| CHPP_LOGD( |
| "WiFi ConfigurePassiveLocationListener request accepted at service"); |
| } |
| } |
| |
| /** |
| * Handles the State Resync service notification. |
| * |
| * This function is called from chppDispatchGnssNotification(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssStateResyncNotification( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) { |
| UNUSED_VAR(buf); |
| UNUSED_VAR(len); |
| if (clientContext->client.openState == CHPP_OPEN_STATE_WAITING_TO_OPEN) { |
| // If the GNSS client is waiting for the open to proceed, the CHRE handler |
| // for requestStateResync() may fail, so we set a flag to process it later |
| // when the open has succeeded. |
| clientContext->requestStateResyncPending = true; |
| } else { |
| gCallbacks->requestStateResync(); |
| clientContext->requestStateResyncPending = false; |
| } |
| } |
| |
| /** |
| * Handles the Location Result service notification. |
| * |
| * This function is called from chppDispatchGnssNotification(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssLocationResultNotification( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) { |
| UNUSED_VAR(clientContext); |
| CHPP_LOGD("chppGnssLocationResultNotification received data len=%" PRIuSIZE, |
| len); |
| |
| buf += sizeof(struct ChppAppHeader); |
| len -= sizeof(struct ChppAppHeader); |
| |
| struct chreGnssLocationEvent *chre = |
| chppGnssLocationEventToChre((struct ChppGnssLocationEvent *)buf, len); |
| |
| if (chre == NULL) { |
| CHPP_LOGE("Location result conversion failed: len=%" PRIuSIZE, len); |
| } else { |
| gCallbacks->locationEventCallback(chre); |
| } |
| } |
| |
| /** |
| * Handles the Measurement Result service notification. |
| * |
| * This function is called from chppDispatchGnssNotification(). |
| * |
| * @param clientContext Maintains status for each client instance. |
| * @param buf Input data. Cannot be null. |
| * @param len Length of input data in bytes. |
| */ |
| static void chppGnssMeasurementResultNotification( |
| struct ChppGnssClientState *clientContext, uint8_t *buf, size_t len) { |
| UNUSED_VAR(clientContext); |
| CHPP_LOGD( |
| "chppGnssMeasurementResultNotification received data len=%" PRIuSIZE, |
| len); |
| |
| buf += sizeof(struct ChppAppHeader); |
| len -= sizeof(struct ChppAppHeader); |
| |
| struct chreGnssDataEvent *chre = |
| chppGnssDataEventToChre((struct ChppGnssDataEvent *)buf, len); |
| |
| if (chre == NULL) { |
| CHPP_LOGE("Measurement result conversion failed len=%" PRIuSIZE, len); |
| } else { |
| gCallbacks->measurementEventCallback(chre); |
| } |
| } |
| |
| /** |
| * Initializes the GNSS client upon an open request from CHRE and responds |
| * with the result. |
| * |
| * @param systemApi CHRE system function pointers. |
| * @param callbacks CHRE entry points. |
| * |
| * @return True if successful. False otherwise. |
| */ |
| static bool chppGnssClientOpen(const struct chrePalSystemApi *systemApi, |
| const struct chrePalGnssCallbacks *callbacks) { |
| CHPP_DEBUG_NOT_NULL(systemApi); |
| CHPP_DEBUG_NOT_NULL(callbacks); |
| |
| bool result = false; |
| gSystemApi = systemApi; |
| gCallbacks = callbacks; |
| |
| CHPP_LOGD("GNSS client opening"); |
| if (gGnssClientContext.client.appContext == NULL) { |
| CHPP_LOGE("GNSS client app is null"); |
| } else { |
| if (chppWaitForDiscoveryComplete(gGnssClientContext.client.appContext, |
| CHPP_GNSS_DISCOVERY_TIMEOUT_MS)) { |
| result = chppClientSendOpenRequest( |
| &gGnssClientContext.client, |
| &gGnssClientContext.outReqStates[CHPP_GNSS_OPEN], CHPP_GNSS_OPEN, |
| /*blocking=*/true); |
| } |
| |
| // Since CHPP_GNSS_DEFAULT_CAPABILITIES is mandatory, we can always |
| // pseudo-open and return true. Otherwise, these should have been gated. |
| chppClientPseudoOpen(&gGnssClientContext.client); |
| result = true; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Deinitializes the GNSS client. |
| */ |
| static void chppGnssClientClose(void) { |
| // Remote |
| struct ChppAppHeader *request = chppAllocClientRequestCommand( |
| &gGnssClientContext.client, CHPP_GNSS_CLOSE); |
| |
| if (request == NULL) { |
| CHPP_LOG_OOM(); |
| } else if (chppClientSendTimestampedRequestAndWait( |
| &gGnssClientContext.client, |
| &gGnssClientContext.outReqStates[CHPP_GNSS_CLOSE], request, |
| sizeof(*request))) { |
| gGnssClientContext.client.openState = CHPP_OPEN_STATE_CLOSED; |
| gGnssClientContext.capabilities = CHRE_GNSS_CAPABILITIES_NONE; |
| gGnssClientContext.capabilitiesValid = false; |
| chppClientCloseOpenRequests(&gGnssClientContext.client, &kGnssClientConfig, |
| true /* clearOnly */); |
| } |
| } |
| |
| /** |
| * Retrieves a set of flags indicating the GNSS features supported by the |
| * current implementation. |
| * |
| * @return Capabilities flags. |
| */ |
| static uint32_t chppGnssClientGetCapabilities(void) { |
| uint32_t capabilities = CHPP_GNSS_DEFAULT_CAPABILITIES; |
| |
| if (gGnssClientContext.capabilitiesValid) { |
| // Result already cached |
| capabilities = gGnssClientContext.capabilities; |
| |
| } else { |
| struct ChppAppHeader *request = chppAllocClientRequestCommand( |
| &gGnssClientContext.client, CHPP_GNSS_GET_CAPABILITIES); |
| |
| if (request == NULL) { |
| CHPP_LOG_OOM(); |
| } else { |
| if (chppClientSendTimestampedRequestAndWait( |
| &gGnssClientContext.client, |
| &gGnssClientContext.outReqStates[CHPP_GNSS_GET_CAPABILITIES], |
| request, sizeof(*request))) { |
| // Success. gGnssClientContext.capabilities is now populated |
| if (gGnssClientContext.capabilitiesValid) { |
| capabilities = gGnssClientContext.capabilities; |
| } |
| } |
| } |
| } |
| |
| return capabilities; |
| } |
| |
| /** |
| * Start/stop/modify the GNSS location session used for clients of the CHRE |
| * API. |
| * |
| * @param enable true to start/modify the session, false to stop the |
| * session. If false, other parameters are ignored. |
| * @param minIntervalMs See chreGnssLocationSessionStartAsync() |
| * @param minTimeToNextFixMs See chreGnssLocationSessionStartAsync() |
| * |
| * @return True indicates the request was sent off to the service. |
| */ |
| |
| static bool chppGnssClientControlLocationSession(bool enable, |
| uint32_t minIntervalMs, |
| uint32_t minTimeToNextFixMs) { |
| bool result = false; |
| |
| struct ChppGnssControlLocationSessionRequest *request = |
| chppAllocClientRequestFixed(&gGnssClientContext.client, |
| struct ChppGnssControlLocationSessionRequest); |
| |
| if (request == NULL) { |
| CHPP_LOG_OOM(); |
| } else { |
| request->header.command = CHPP_GNSS_CONTROL_LOCATION_SESSION; |
| request->params.enable = enable; |
| request->params.minIntervalMs = minIntervalMs; |
| request->params.minTimeToNextFixMs = minTimeToNextFixMs; |
| |
| result = chppClientSendTimestampedRequestOrFail( |
| &gGnssClientContext.client, |
| &gGnssClientContext.outReqStates[CHPP_GNSS_CONTROL_LOCATION_SESSION], |
| request, sizeof(*request), CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Releases the memory held for the location event callback. |
| * |
| * @param event Location event to be released. |
| */ |
| static void chppGnssClientReleaseLocationEvent( |
| struct chreGnssLocationEvent *event) { |
| CHPP_FREE_AND_NULLIFY(event); |
| } |
| |
| /** |
| * Start/stop/modify the raw GNSS measurement session used for clients of the |
| * CHRE API. |
| * |
| * @param enable true to start/modify the session, false to stop the |
| * session. If false, other parameters are ignored. |
| * @param minIntervalMs See chreGnssMeasurementSessionStartAsync() |
| * |
| * @return True indicates the request was sent off to the service. |
| */ |
| |
| static bool chppGnssClientControlMeasurementSession(bool enable, |
| uint32_t minIntervalMs) { |
| bool result = false; |
| |
| struct ChppGnssControlMeasurementSessionRequest *request = |
| chppAllocClientRequestFixed( |
| &gGnssClientContext.client, |
| struct ChppGnssControlMeasurementSessionRequest); |
| |
| if (request == NULL) { |
| CHPP_LOG_OOM(); |
| } else { |
| request->header.command = CHPP_GNSS_CONTROL_MEASUREMENT_SESSION; |
| request->params.enable = enable; |
| request->params.minIntervalMs = minIntervalMs; |
| |
| result = chppClientSendTimestampedRequestOrFail( |
| &gGnssClientContext.client, |
| &gGnssClientContext.outReqStates[CHPP_GNSS_CONTROL_MEASUREMENT_SESSION], |
| request, sizeof(*request), CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Releases the memory held for the measurement event callback. |
| * |
| * @param event Measurement event to be released. |
| */ |
| static void chppGnssClientReleaseMeasurementDataEvent( |
| struct chreGnssDataEvent *event) { |
| if (event->measurement_count > 0) { |
| void *measurements = CHPP_CONST_CAST_POINTER(event->measurements); |
| CHPP_FREE_AND_NULLIFY(measurements); |
| } |
| |
| CHPP_FREE_AND_NULLIFY(event); |
| } |
| |
| /** |
| * Starts/stops opportunistic delivery of location fixes. |
| * |
| * @param enable true to turn the passive location listener on, false to |
| * turn it off. |
| * |
| * @return True indicates the request was sent off to the service. |
| */ |
| static bool chppGnssClientConfigurePassiveLocationListener(bool enable) { |
| bool result = false; |
| |
| struct ChppGnssConfigurePassiveLocationListenerRequest *request = |
| chppAllocClientRequestFixed( |
| &gGnssClientContext.client, |
| struct ChppGnssConfigurePassiveLocationListenerRequest); |
| |
| if (request == NULL) { |
| CHPP_LOG_OOM(); |
| } else { |
| request->header.command = CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER; |
| request->params.enable = enable; |
| |
| result = chppClientSendTimestampedRequestOrFail( |
| &gGnssClientContext.client, |
| &gGnssClientContext |
| .outReqStates[CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER], |
| request, sizeof(*request), CHPP_REQUEST_TIMEOUT_DEFAULT); |
| } |
| |
| return result; |
| } |
| |
| /************************************************ |
| * Public Functions |
| ***********************************************/ |
| |
| void chppRegisterGnssClient(struct ChppAppState *appContext) { |
| memset(&gGnssClientContext, 0, sizeof(gGnssClientContext)); |
| chppRegisterClient(appContext, (void *)&gGnssClientContext, |
| &gGnssClientContext.client, |
| gGnssClientContext.outReqStates, &kGnssClientConfig); |
| } |
| |
| void chppDeregisterGnssClient(struct ChppAppState *appContext) { |
| // TODO |
| |
| UNUSED_VAR(appContext); |
| } |
| |
| struct ChppEndpointState *getChppGnssClientState(void) { |
| return &gGnssClientContext.client; |
| } |
| |
| #ifdef CHPP_CLIENT_ENABLED_GNSS |
| |
| #ifdef CHPP_CLIENT_ENABLED_CHRE_GNSS |
| const struct chrePalGnssApi *chrePalGnssGetApi(uint32_t requestedApiVersion) { |
| #else |
| const struct chrePalGnssApi *chppPalGnssGetApi(uint32_t requestedApiVersion) { |
| #endif |
| |
| static const struct chrePalGnssApi api = { |
| .moduleVersion = CHPP_PAL_GNSS_API_VERSION, |
| .open = chppGnssClientOpen, |
| .close = chppGnssClientClose, |
| .getCapabilities = chppGnssClientGetCapabilities, |
| .controlLocationSession = chppGnssClientControlLocationSession, |
| .releaseLocationEvent = chppGnssClientReleaseLocationEvent, |
| .controlMeasurementSession = chppGnssClientControlMeasurementSession, |
| .releaseMeasurementDataEvent = chppGnssClientReleaseMeasurementDataEvent, |
| .configurePassiveLocationListener = |
| chppGnssClientConfigurePassiveLocationListener, |
| }; |
| |
| CHPP_STATIC_ASSERT( |
| CHRE_PAL_GNSS_API_CURRENT_VERSION == CHPP_PAL_GNSS_API_VERSION, |
| "A newer CHRE PAL API version is available. Please update."); |
| |
| if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(api.moduleVersion, |
| requestedApiVersion)) { |
| return NULL; |
| } else { |
| return &api; |
| } |
| } |
| |
| #endif |