• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/services/gnss.h"
18 
19 #include <inttypes.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 
23 #include "chpp/common/gnss.h"
24 #include "chpp/common/gnss_types.h"
25 #include "chpp/common/standard_uuids.h"
26 #include "chpp/log.h"
27 #include "chpp/macros.h"
28 #include "chpp/services.h"
29 #include "chre/pal/gnss.h"
30 
31 /************************************************
32  *  Prototypes
33  ***********************************************/
34 
35 static enum ChppAppErrorCode chppDispatchGnssRequest(void *serviceContext,
36                                                      uint8_t *buf, size_t len);
37 static void chppGnssServiceNotifyReset(void *serviceContext);
38 
39 /************************************************
40  *  Private Definitions
41  ***********************************************/
42 
43 /**
44  * Configuration parameters for this service
45  */
46 static const struct ChppService kGnssServiceConfig = {
47     .descriptor.uuid = CHPP_UUID_GNSS_STANDARD,
48 
49     // Human-readable name
50     .descriptor.name = "GNSS",
51 
52     // Version
53     .descriptor.version.major = 1,
54     .descriptor.version.minor = 0,
55     .descriptor.version.patch = 0,
56 
57     // Notifies service if CHPP is reset
58     .resetNotifierFunctionPtr = &chppGnssServiceNotifyReset,
59 
60     // Client request dispatch function pointer
61     .requestDispatchFunctionPtr = &chppDispatchGnssRequest,
62 
63     // Client notification dispatch function pointer
64     .notificationDispatchFunctionPtr = NULL,  // Not supported
65 
66     // Client timeout function pointer
67     .timeoutFunctionPtr = NULL,  // Not used
68 
69     // Min length is the entire header
70     .minLength = sizeof(struct ChppAppHeader),
71 };
72 
73 /**
74  * Structure to maintain state for the GNSS service and its Request/Response
75  * (RR) functionality.
76  */
77 struct ChppGnssServiceState {
78   struct ChppEndpointState service;  // CHPP service state
79   const struct chrePalGnssApi *api;  // GNSS PAL API
80 
81   // Based on chre/pal/gnss.h and chrePalGnssApi
82   struct ChppIncomingRequestState open;             // Service init state
83   struct ChppIncomingRequestState close;            // Service deinit state
84   struct ChppIncomingRequestState getCapabilities;  // Get Capabilities state
85   struct ChppIncomingRequestState
86       controlLocationSession;  // Control Location measurement state
87   struct ChppIncomingRequestState
88       controlMeasurementSession;  // Control Raw GNSS measurement state
89   struct ChppIncomingRequestState
90       configurePassiveLocationListener;  // Configure Passive location receiving
91                                          // state
92 };
93 
94 // Note: The CHRE PAL API only allows for one definition - see comment in WWAN
95 // service for details.
96 // Note: There is no notion of a cookie in the CHRE GNSS API so we need to use
97 // the global service state (gGnssServiceContext) directly in all callbacks.
98 struct ChppGnssServiceState gGnssServiceContext;
99 
100 /************************************************
101  *  Prototypes
102  ***********************************************/
103 
104 static enum ChppAppErrorCode chppGnssServiceOpen(
105     struct ChppGnssServiceState *gnssServiceContext,
106     struct ChppAppHeader *requestHeader);
107 static enum ChppAppErrorCode chppGnssServiceClose(
108     struct ChppGnssServiceState *gnssServiceContext,
109     struct ChppAppHeader *requestHeader);
110 static enum ChppAppErrorCode chppGnssServiceGetCapabilities(
111     struct ChppGnssServiceState *gnssServiceContext,
112     struct ChppAppHeader *requestHeader);
113 static enum ChppAppErrorCode chppGnssServiceControlLocationSession(
114     struct ChppGnssServiceState *gnssServiceContext,
115     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len);
116 static enum ChppAppErrorCode chppGnssServiceControlMeasurementSession(
117     struct ChppGnssServiceState *gnssServiceContext,
118     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len);
119 static enum ChppAppErrorCode chppGnssServiceConfigurePassiveLocationListener(
120     struct ChppGnssServiceState *gnssServiceContext,
121     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len);
122 
123 static void chppGnssServiceRequestStateResyncCallback(void);
124 static void chppGnssServiceLocationStatusChangeCallback(bool enabled,
125                                                         uint8_t errorCode);
126 static void chppGnssServiceLocationEventCallback(
127     struct chreGnssLocationEvent *event);
128 static void chppGnssServiceMeasurementStatusChangeCallback(bool enabled,
129                                                            uint8_t errorCode);
130 static void chppGnssServiceMeasurementEventCallback(
131     struct chreGnssDataEvent *event);
132 
133 /************************************************
134  *  Private Functions
135  ***********************************************/
136 
137 /**
138  * Dispatches a client request from the transport layer that is determined to be
139  * for the GNSS service. If the result of the dispatch is an error, this
140  * function responds to the client with the same error.
141  *
142  * This function is called from the app layer using its function pointer given
143  * during service registration.
144  *
145  * @param serviceContext Maintains status for each service instance.
146  * @param buf Input data. Cannot be null.
147  * @param len Length of input data in bytes.
148  *
149  * @return Indicates the result of this function call.
150  */
chppDispatchGnssRequest(void * serviceContext,uint8_t * buf,size_t len)151 static enum ChppAppErrorCode chppDispatchGnssRequest(void *serviceContext,
152                                                      uint8_t *buf, size_t len) {
153   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
154   buf += sizeof(struct ChppAppHeader);
155   len -= sizeof(struct ChppAppHeader);
156 
157   struct ChppGnssServiceState *gnssServiceContext =
158       (struct ChppGnssServiceState *)serviceContext;
159   struct ChppIncomingRequestState *inReqState = NULL;
160   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
161   bool dispatched = true;
162 
163   switch (rxHeader->command) {
164     case CHPP_GNSS_OPEN: {
165       inReqState = &gnssServiceContext->open;
166       chppTimestampIncomingRequest(inReqState, rxHeader);
167       error = chppGnssServiceOpen(gnssServiceContext, rxHeader);
168       break;
169     }
170 
171     case CHPP_GNSS_CLOSE: {
172       inReqState = &gnssServiceContext->close;
173       chppTimestampIncomingRequest(inReqState, rxHeader);
174       error = chppGnssServiceClose(gnssServiceContext, rxHeader);
175       break;
176     }
177 
178     case CHPP_GNSS_GET_CAPABILITIES: {
179       inReqState = &gnssServiceContext->getCapabilities;
180       chppTimestampIncomingRequest(inReqState, rxHeader);
181       error = chppGnssServiceGetCapabilities(gnssServiceContext, rxHeader);
182       break;
183     }
184 
185     case CHPP_GNSS_CONTROL_LOCATION_SESSION: {
186       inReqState = &gnssServiceContext->controlLocationSession;
187       chppTimestampIncomingRequest(inReqState, rxHeader);
188       error = chppGnssServiceControlLocationSession(gnssServiceContext,
189                                                     rxHeader, buf, len);
190       break;
191     }
192 
193     case CHPP_GNSS_CONTROL_MEASUREMENT_SESSION: {
194       inReqState = &gnssServiceContext->controlMeasurementSession;
195       chppTimestampIncomingRequest(inReqState, rxHeader);
196       error = chppGnssServiceControlMeasurementSession(gnssServiceContext,
197                                                        rxHeader, buf, len);
198       break;
199     }
200 
201     case CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER: {
202       inReqState = &gnssServiceContext->configurePassiveLocationListener;
203       chppTimestampIncomingRequest(inReqState, rxHeader);
204       error = chppGnssServiceConfigurePassiveLocationListener(
205           gnssServiceContext, rxHeader, buf, len);
206       break;
207     }
208 
209     default: {
210       dispatched = false;
211       error = CHPP_APP_ERROR_INVALID_COMMAND;
212       break;
213     }
214   }
215 
216   if (dispatched == true && error != CHPP_APP_ERROR_NONE) {
217     // Request was dispatched but an error was returned. Close out
218     // chppTimestampIncomingRequest()
219     chppTimestampOutgoingResponse(inReqState);
220   }
221 
222   return error;
223 }
224 
225 /**
226  * Initializes the GNSS service upon an open request from the client and
227  * responds to the client with the result.
228  *
229  * @param serviceContext Maintains status for each service instance.
230  * @param requestHeader App layer header of the request.
231  *
232  * @return Indicates the result of this function call.
233  */
chppGnssServiceOpen(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader)234 static enum ChppAppErrorCode chppGnssServiceOpen(
235     struct ChppGnssServiceState *gnssServiceContext,
236     struct ChppAppHeader *requestHeader) {
237   static const struct chrePalGnssCallbacks palCallbacks = {
238       .requestStateResync = chppGnssServiceRequestStateResyncCallback,
239       .locationStatusChangeCallback =
240           chppGnssServiceLocationStatusChangeCallback,
241       .locationEventCallback = chppGnssServiceLocationEventCallback,
242       .measurementStatusChangeCallback =
243           chppGnssServiceMeasurementStatusChangeCallback,
244       .measurementEventCallback = chppGnssServiceMeasurementEventCallback,
245   };
246 
247   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
248 
249   if (gnssServiceContext->service.openState == CHPP_OPEN_STATE_OPENED) {
250     CHPP_DEBUG_ASSERT_LOG(false, "GNSS service already open");
251     error = CHPP_APP_ERROR_INVALID_COMMAND;
252 
253   } else if (!gnssServiceContext->api->open(
254                  gnssServiceContext->service.appContext->systemApi,
255                  &palCallbacks)) {
256     CHPP_DEBUG_ASSERT_LOG(false, "GNSS PAL open failed");
257     error = CHPP_APP_ERROR_BEYOND_CHPP;
258 
259   } else {
260     CHPP_LOGD("GNSS service opened");
261     gnssServiceContext->service.openState = CHPP_OPEN_STATE_OPENED;
262 
263     struct ChppAppHeader *response =
264         chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
265     size_t responseLen = sizeof(*response);
266 
267     if (response == NULL) {
268       CHPP_LOG_OOM();
269       error = CHPP_APP_ERROR_OOM;
270     } else {
271       chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
272                                         &gnssServiceContext->open, response,
273                                         responseLen);
274     }
275   }
276 
277   return error;
278 }
279 
280 /**
281  * Deinitializes the GNSS service.
282  *
283  * @param serviceContext Maintains status for each service instance.
284  * @param requestHeader App layer header of the request.
285  *
286  * @return Indicates the result of this function call.
287  */
chppGnssServiceClose(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader)288 static enum ChppAppErrorCode chppGnssServiceClose(
289     struct ChppGnssServiceState *gnssServiceContext,
290     struct ChppAppHeader *requestHeader) {
291   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
292 
293   gnssServiceContext->api->close();
294   gnssServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED;
295 
296   CHPP_LOGD("GNSS service closed");
297 
298   struct ChppAppHeader *response =
299       chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
300   size_t responseLen = sizeof(*response);
301 
302   if (response == NULL) {
303     CHPP_LOG_OOM();
304     error = CHPP_APP_ERROR_OOM;
305   } else {
306     chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
307                                       &gnssServiceContext->close, response,
308                                       responseLen);
309   }
310 
311   return error;
312 }
313 
314 /**
315  * Notifies the service of an incoming reset.
316  *
317  * @param serviceContext Maintains status for each service instance.
318  */
chppGnssServiceNotifyReset(void * serviceContext)319 static void chppGnssServiceNotifyReset(void *serviceContext) {
320   struct ChppGnssServiceState *gnssServiceContext =
321       (struct ChppGnssServiceState *)serviceContext;
322 
323   if (gnssServiceContext->service.openState != CHPP_OPEN_STATE_OPENED) {
324     CHPP_LOGW("GNSS service reset but wasn't open");
325   } else {
326     CHPP_LOGD("GNSS service reset. Closing");
327     gnssServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED;
328     gnssServiceContext->api->close();
329   }
330 }
331 
332 /**
333  * Retrieves a set of flags indicating the GNSS features supported by the
334  * current implementation.
335  *
336  * @param serviceContext Maintains status for each service instance.
337  * @param requestHeader App layer header of the request.
338  *
339  * @return Indicates the result of this function call.
340  */
chppGnssServiceGetCapabilities(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader)341 static enum ChppAppErrorCode chppGnssServiceGetCapabilities(
342     struct ChppGnssServiceState *gnssServiceContext,
343     struct ChppAppHeader *requestHeader) {
344   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
345 
346   struct ChppGnssGetCapabilitiesResponse *response = chppAllocResponseFixed(
347       requestHeader, struct ChppGnssGetCapabilitiesResponse);
348   size_t responseLen = sizeof(*response);
349 
350   if (response == NULL) {
351     CHPP_LOG_OOM();
352     error = CHPP_APP_ERROR_OOM;
353   } else {
354     response->params.capabilities = gnssServiceContext->api->getCapabilities();
355 
356     CHPP_LOGD("chppGnssServiceGetCapabilities returning 0x%" PRIx32
357               ", %" PRIuSIZE " bytes",
358               response->params.capabilities, responseLen);
359     chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
360                                       &gnssServiceContext->getCapabilities,
361                                       response, responseLen);
362   }
363 
364   return error;
365 }
366 
367 /**
368  * Start/stop/modify the GNSS location session.
369  *
370  * This function returns an error code synchronously.
371  * A subsequent call to chppGnssServiceLocationStatusChangeCallback() will be
372  * used to communicate the result of this request (as a service response).
373  * A subsequent call to chppGnssServiceLocationEventCallback() will be used to
374  * communicate the location fixes (as service notifications).
375  *
376  * @param serviceContext Maintains status for each service instance.
377  * @param requestHeader App layer header of the request.
378  * @param buf Input data. Cannot be null.
379  * @param len Length of input data in bytes.
380  *
381  * @return Indicates the result of this function call.
382  */
chppGnssServiceControlLocationSession(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader,uint8_t * buf,size_t len)383 static enum ChppAppErrorCode chppGnssServiceControlLocationSession(
384     struct ChppGnssServiceState *gnssServiceContext,
385     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) {
386   UNUSED_VAR(requestHeader);
387   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
388 
389   if (len < sizeof(struct ChppGnssControlLocationSessionParameters)) {
390     error = CHPP_APP_ERROR_INVALID_ARG;
391 
392   } else {
393     struct ChppGnssControlLocationSessionParameters *parameters =
394         (struct ChppGnssControlLocationSessionParameters *)buf;
395 
396     if (!gnssServiceContext->api->controlLocationSession(
397             parameters->enable, parameters->minIntervalMs,
398             parameters->minTimeToNextFixMs)) {
399       error = CHPP_APP_ERROR_UNSPECIFIED;
400     }
401   }
402 
403   return error;
404 }
405 
406 /**
407  * Start/stop/modify the raw GNSS measurement session.
408  *
409  * This function returns an error code synchronously.
410  * A subsequent call to chppGnssServiceMeasurementStatusChangeCallback() will be
411  * used to communicate the result of this request (as a service response).
412  * A subsequent call to chppGnssServiceMeasurementEventCallback() will be used
413  * to communicate the measurements (as service notifications).
414  *
415  * @param serviceContext Maintains status for each service instance.
416  * @param requestHeader App layer header of the request.
417  * @param buf Input data. Cannot be null.
418  * @param len Length of input data in bytes.
419  *
420  * @return Indicates the result of this function call.
421  */
chppGnssServiceControlMeasurementSession(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader,uint8_t * buf,size_t len)422 static enum ChppAppErrorCode chppGnssServiceControlMeasurementSession(
423     struct ChppGnssServiceState *gnssServiceContext,
424     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) {
425   UNUSED_VAR(requestHeader);
426   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
427 
428   if (len < sizeof(struct ChppGnssControlMeasurementSessionParameters)) {
429     error = CHPP_APP_ERROR_INVALID_ARG;
430 
431   } else {
432     struct ChppGnssControlMeasurementSessionParameters *parameters =
433         (struct ChppGnssControlMeasurementSessionParameters *)buf;
434 
435     if (!gnssServiceContext->api->controlMeasurementSession(
436             parameters->enable, parameters->minIntervalMs)) {
437       error = CHPP_APP_ERROR_UNSPECIFIED;
438     }
439   }
440 
441   return error;
442 }
443 
444 /**
445  * Configures whether to opportunistically deliver any location fixes produced
446  * for other clients of the GNSS engine.
447  *
448  * This function returns an error code synchronously.
449  * A subsequent call to chppGnssServiceLocationEventCallback() will be used to
450  * communicate the location fixes (as service notifications).
451  *
452  * @param serviceContext Maintains status for each service instance.
453  * @param requestHeader App layer header of the request.
454  * @param buf Input data. Cannot be null.
455  * @param len Length of input data in bytes.
456  *
457  * @return Indicates the result of this function call.
458  */
chppGnssServiceConfigurePassiveLocationListener(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader,uint8_t * buf,size_t len)459 static enum ChppAppErrorCode chppGnssServiceConfigurePassiveLocationListener(
460     struct ChppGnssServiceState *gnssServiceContext,
461     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) {
462   UNUSED_VAR(requestHeader);
463   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
464 
465   if (len < sizeof(struct ChppGnssConfigurePassiveLocationListenerParameters)) {
466     error = CHPP_APP_ERROR_INVALID_ARG;
467   } else {
468     struct ChppGnssConfigurePassiveLocationListenerParameters *parameters =
469         (struct ChppGnssConfigurePassiveLocationListenerParameters *)buf;
470 
471     if (!gnssServiceContext->api->configurePassiveLocationListener(
472             parameters->enable)) {
473       error = CHPP_APP_ERROR_UNSPECIFIED;
474 
475     } else {
476       struct ChppAppHeader *response =
477           chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
478       size_t responseLen = sizeof(*response);
479 
480       if (response == NULL) {
481         CHPP_LOG_OOM();
482         error = CHPP_APP_ERROR_OOM;
483       } else {
484         chppSendTimestampedResponseOrFail(
485             gnssServiceContext->service.appContext,
486             &gnssServiceContext->configurePassiveLocationListener, response,
487             responseLen);
488       }
489     }
490   }
491 
492   return error;
493 }
494 
495 /**
496  * GNSS PAL callback to request that the core CHRE system re-send requests for
497  * any active sessions and its current passive location listener setting.
498  */
chppGnssServiceRequestStateResyncCallback(void)499 static void chppGnssServiceRequestStateResyncCallback(void) {
500   struct ChppAppHeader *notification =
501       chppAllocServiceNotificationFixed(struct ChppAppHeader);
502   size_t notificationLen = sizeof(*notification);
503 
504   if (notification == NULL) {
505     CHPP_LOG_OOM();
506     CHPP_ASSERT(false);
507 
508   } else {
509     notification->handle = gGnssServiceContext.service.handle;
510     notification->command = CHPP_GNSS_REQUEST_STATE_RESYNC_NOTIFICATION;
511 
512     chppEnqueueTxDatagramOrFail(
513         gGnssServiceContext.service.appContext->transportContext, notification,
514         notificationLen);
515   }
516 }
517 
518 /**
519  * GNSS PAL callback to inform the CHRE of the result of changes to the location
520  * session status.
521  */
chppGnssServiceLocationStatusChangeCallback(bool enabled,uint8_t errorCode)522 static void chppGnssServiceLocationStatusChangeCallback(bool enabled,
523                                                         uint8_t errorCode) {
524   // Recreate request header
525   struct ChppAppHeader requestHeader = {
526       .handle = gGnssServiceContext.service.handle,
527       .transaction = gGnssServiceContext.controlLocationSession.transaction,
528       .command = CHPP_GNSS_CONTROL_LOCATION_SESSION,
529   };
530 
531   struct ChppGnssControlLocationSessionResponse *response =
532       chppAllocResponseFixed(&requestHeader,
533                              struct ChppGnssControlLocationSessionResponse);
534   size_t responseLen = sizeof(*response);
535 
536   if (response == NULL) {
537     CHPP_LOG_OOM();
538     CHPP_ASSERT(false);
539 
540   } else {
541     response->enabled = enabled;
542     response->errorCode = errorCode;
543 
544     chppSendTimestampedResponseOrFail(
545         gGnssServiceContext.service.appContext,
546         &gGnssServiceContext.controlLocationSession, response, responseLen);
547   }
548 }
549 
550 /**
551  * GNSS PAL callback to pass GNSS location fixes to the core CHRE system.
552  */
chppGnssServiceLocationEventCallback(struct chreGnssLocationEvent * event)553 static void chppGnssServiceLocationEventCallback(
554     struct chreGnssLocationEvent *event) {
555   // Craft response per parser script
556   struct ChppGnssLocationEventWithHeader *notification = NULL;
557   size_t notificationLen = 0;
558 
559   if (!chppGnssLocationEventFromChre(event, &notification, &notificationLen)) {
560     CHPP_LOGE("LocationEvent conversion failed (OOM?)");
561 
562     notification = chppMalloc(sizeof(struct ChppAppHeader));
563     if (notification == NULL) {
564       CHPP_LOG_OOM();
565     } else {
566       notificationLen = sizeof(struct ChppAppHeader);
567     }
568   }
569 
570   if (notification != NULL) {
571     notification->header.handle = gGnssServiceContext.service.handle;
572     notification->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION;
573     notification->header.transaction =
574         0;  // Because we don't know this is in response to a Location Session
575             // or Passive Location Listener
576     notification->header.error =
577         (notificationLen > sizeof(struct ChppAppHeader))
578             ? CHPP_APP_ERROR_NONE
579             : CHPP_APP_ERROR_CONVERSION_FAILED;
580     notification->header.command = CHPP_GNSS_LOCATION_RESULT_NOTIFICATION;
581 
582     chppEnqueueTxDatagramOrFail(
583         gGnssServiceContext.service.appContext->transportContext, notification,
584         notificationLen);
585   }
586 
587   gGnssServiceContext.api->releaseLocationEvent(event);
588 }
589 
590 /**
591  * GNSS PAL callback to inform the CHRE of the result of changes to the raw GNSS
592  * measurement session status.
593  */
chppGnssServiceMeasurementStatusChangeCallback(bool enabled,uint8_t errorCode)594 static void chppGnssServiceMeasurementStatusChangeCallback(bool enabled,
595                                                            uint8_t errorCode) {
596   // Recreate request header
597   struct ChppAppHeader requestHeader = {
598       .handle = gGnssServiceContext.service.handle,
599       .transaction = gGnssServiceContext.controlMeasurementSession.transaction,
600       .command = CHPP_GNSS_CONTROL_MEASUREMENT_SESSION,
601   };
602 
603   struct ChppGnssControlMeasurementSessionResponse *response =
604       chppAllocResponseFixed(&requestHeader,
605                              struct ChppGnssControlMeasurementSessionResponse);
606   size_t responseLen = sizeof(*response);
607 
608   if (response == NULL) {
609     CHPP_LOG_OOM();
610     CHPP_ASSERT(false);
611 
612   } else {
613     response->enabled = enabled;
614     response->errorCode = errorCode;
615 
616     chppSendTimestampedResponseOrFail(
617         gGnssServiceContext.service.appContext,
618         &gGnssServiceContext.controlMeasurementSession, response, responseLen);
619   }
620 }
621 
622 /**
623  * GNSS PAL callback to pass raw GNSS measurement data to the core CHRE system.
624  */
chppGnssServiceMeasurementEventCallback(struct chreGnssDataEvent * event)625 static void chppGnssServiceMeasurementEventCallback(
626     struct chreGnssDataEvent *event) {
627   // Craft response per parser script
628   struct ChppGnssDataEventWithHeader *notification = NULL;
629   size_t notificationLen = 0;
630 
631   if (!chppGnssDataEventFromChre(event, &notification, &notificationLen)) {
632     CHPP_LOGE("DataEvent conversion failed (OOM?) ID=%" PRIu8,
633               gGnssServiceContext.controlMeasurementSession.transaction);
634 
635     notification = chppMalloc(sizeof(struct ChppAppHeader));
636     if (notification == NULL) {
637       CHPP_LOG_OOM();
638     } else {
639       notificationLen = sizeof(struct ChppAppHeader);
640     }
641   }
642 
643   if (notification != NULL) {
644     notification->header.handle = gGnssServiceContext.service.handle;
645     notification->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION;
646     notification->header.transaction =
647         gGnssServiceContext.controlMeasurementSession.transaction;
648     notification->header.error =
649         (notificationLen > sizeof(struct ChppAppHeader))
650             ? CHPP_APP_ERROR_NONE
651             : CHPP_APP_ERROR_CONVERSION_FAILED;
652     notification->header.command = CHPP_GNSS_MEASUREMENT_RESULT_NOTIFICATION;
653 
654     chppEnqueueTxDatagramOrFail(
655         gGnssServiceContext.service.appContext->transportContext, notification,
656         notificationLen);
657   }
658 
659   gGnssServiceContext.api->releaseMeasurementDataEvent(event);
660 }
661 
662 /************************************************
663  *  Public Functions
664  ***********************************************/
665 
chppRegisterGnssService(struct ChppAppState * appContext)666 void chppRegisterGnssService(struct ChppAppState *appContext) {
667   gGnssServiceContext.api = chrePalGnssGetApi(CHPP_PAL_GNSS_API_VERSION);
668 
669   if (gGnssServiceContext.api == NULL) {
670     CHPP_DEBUG_ASSERT_LOG(false,
671                           "GNSS PAL API incompatible. Cannot register service");
672 
673   } else {
674     chppRegisterService(appContext, (void *)&gGnssServiceContext,
675                         &gGnssServiceContext.service, NULL /*outReqState*/,
676                         &kGnssServiceConfig);
677     CHPP_DEBUG_ASSERT(gGnssServiceContext.service.handle);
678   }
679 }
680 
chppDeregisterGnssService(struct ChppAppState * appContext)681 void chppDeregisterGnssService(struct ChppAppState *appContext) {
682   // TODO
683 
684   UNUSED_VAR(appContext);
685 }
686