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