1 /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30 #define LOG_NDDEBUG 0
31 #define LOG_TAG "LocSvc_eng_nmea"
32 #define GPS_PRN_START 1
33 #define GPS_PRN_END 32
34 #define GLONASS_PRN_START 65
35 #define GLONASS_PRN_END 96
36 #include <loc_eng.h>
37 #include <loc_eng_nmea.h>
38 #include <math.h>
39 #include "log_util.h"
40
41 /*===========================================================================
42 FUNCTION loc_eng_nmea_send
43
44 DESCRIPTION
45 send out NMEA sentence
46
47 DEPENDENCIES
48 NONE
49
50 RETURN VALUE
51 Total length of the nmea sentence
52
53 SIDE EFFECTS
54 N/A
55
56 ===========================================================================*/
loc_eng_nmea_send(char * pNmea,int length,loc_eng_data_s_type * loc_eng_data_p)57 void loc_eng_nmea_send(char *pNmea, int length, loc_eng_data_s_type *loc_eng_data_p)
58 {
59 struct timeval tv;
60 gettimeofday(&tv, (struct timezone *) NULL);
61 int64_t now = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
62 CALLBACK_LOG_CALLFLOW("nmea_cb", %p, pNmea);
63 if (loc_eng_data_p->nmea_cb != NULL)
64 loc_eng_data_p->nmea_cb(now, pNmea, length);
65 LOC_LOGD("NMEA <%s", pNmea);
66 }
67
68 /*===========================================================================
69 FUNCTION loc_eng_nmea_put_checksum
70
71 DESCRIPTION
72 Generate NMEA sentences generated based on position report
73
74 DEPENDENCIES
75 NONE
76
77 RETURN VALUE
78 Total length of the nmea sentence
79
80 SIDE EFFECTS
81 N/A
82
83 ===========================================================================*/
loc_eng_nmea_put_checksum(char * pNmea,int maxSize)84 int loc_eng_nmea_put_checksum(char *pNmea, int maxSize)
85 {
86 uint8_t checksum = 0;
87 int length = 0;
88
89 pNmea++; //skip the $
90 while (*pNmea != '\0')
91 {
92 checksum ^= *pNmea++;
93 length++;
94 }
95
96 int checksumLength = snprintf(pNmea,(maxSize-length-1),"*%02X\r\n", checksum);
97 return (length + checksumLength);
98 }
99
100 /*===========================================================================
101 FUNCTION loc_eng_nmea_generate_pos
102
103 DESCRIPTION
104 Generate NMEA sentences generated based on position report
105
106 DEPENDENCIES
107 NONE
108
109 RETURN VALUE
110 0
111
112 SIDE EFFECTS
113 N/A
114
115 ===========================================================================*/
loc_eng_nmea_generate_pos(loc_eng_data_s_type * loc_eng_data_p,const UlpLocation & location,const GpsLocationExtended & locationExtended,unsigned char generate_nmea)116 void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
117 const UlpLocation &location,
118 const GpsLocationExtended &locationExtended,
119 unsigned char generate_nmea)
120 {
121 ENTRY_LOG();
122
123 char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
124 char* pMarker = sentence;
125 int lengthRemaining = sizeof(sentence);
126 int length = 0;
127
128 time_t utcTime(location.gpsLocation.timestamp/1000);
129 tm * pTm = gmtime(&utcTime);
130 int utcYear = pTm->tm_year % 100; // 2 digit year
131 int utcMonth = pTm->tm_mon + 1; // tm_mon starts at zero
132 int utcDay = pTm->tm_mday;
133 int utcHours = pTm->tm_hour;
134 int utcMinutes = pTm->tm_min;
135 int utcSeconds = pTm->tm_sec;
136
137 if (generate_nmea) {
138 // ------------------
139 // ------$GPGSA------
140 // ------------------
141
142 uint32_t svUsedCount = 0;
143 uint32_t svUsedList[32] = {0};
144 uint32_t mask = loc_eng_data_p->sv_used_mask;
145 for (uint8_t i = 1; mask > 0 && svUsedCount < 32; i++)
146 {
147 if (mask & 1)
148 svUsedList[svUsedCount++] = i;
149 mask = mask >> 1;
150 }
151 // clear the cache so they can't be used again
152 loc_eng_data_p->sv_used_mask = 0;
153
154 char fixType;
155 if (svUsedCount == 0)
156 fixType = '1'; // no fix
157 else if (svUsedCount <= 3)
158 fixType = '2'; // 2D fix
159 else
160 fixType = '3'; // 3D fix
161
162 length = snprintf(pMarker, lengthRemaining, "$GPGSA,A,%c,", fixType);
163
164 if (length < 0 || length >= lengthRemaining)
165 {
166 LOC_LOGE("NMEA Error in string formatting");
167 return;
168 }
169 pMarker += length;
170 lengthRemaining -= length;
171
172 for (uint8_t i = 0; i < 12; i++) // only the first 12 sv go in sentence
173 {
174 if (i < svUsedCount)
175 length = snprintf(pMarker, lengthRemaining, "%02d,", svUsedList[i]);
176 else
177 length = snprintf(pMarker, lengthRemaining, ",");
178
179 if (length < 0 || length >= lengthRemaining)
180 {
181 LOC_LOGE("NMEA Error in string formatting");
182 return;
183 }
184 pMarker += length;
185 lengthRemaining -= length;
186 }
187
188 if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
189 { // dop is in locationExtended, (QMI)
190 length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
191 locationExtended.pdop,
192 locationExtended.hdop,
193 locationExtended.vdop);
194 }
195 else if (loc_eng_data_p->pdop > 0 && loc_eng_data_p->hdop > 0 && loc_eng_data_p->vdop > 0)
196 { // dop was cached from sv report (RPC)
197 length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
198 loc_eng_data_p->pdop,
199 loc_eng_data_p->hdop,
200 loc_eng_data_p->vdop);
201 }
202 else
203 { // no dop
204 length = snprintf(pMarker, lengthRemaining, ",,");
205 }
206
207 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
208 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
209
210 // ------------------
211 // ------$GPVTG------
212 // ------------------
213
214 pMarker = sentence;
215 lengthRemaining = sizeof(sentence);
216
217 if (location.gpsLocation.flags & GPS_LOCATION_HAS_BEARING)
218 {
219 float magTrack = location.gpsLocation.bearing;
220 if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
221 {
222 float magTrack = location.gpsLocation.bearing - locationExtended.magneticDeviation;
223 if (magTrack < 0.0)
224 magTrack += 360.0;
225 else if (magTrack > 360.0)
226 magTrack -= 360.0;
227 }
228
229 length = snprintf(pMarker, lengthRemaining, "$GPVTG,%.1lf,T,%.1lf,M,", location.gpsLocation.bearing, magTrack);
230 }
231 else
232 {
233 length = snprintf(pMarker, lengthRemaining, "$GPVTG,,T,,M,");
234 }
235
236 if (length < 0 || length >= lengthRemaining)
237 {
238 LOC_LOGE("NMEA Error in string formatting");
239 return;
240 }
241 pMarker += length;
242 lengthRemaining -= length;
243
244 if (location.gpsLocation.flags & GPS_LOCATION_HAS_SPEED)
245 {
246 float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
247 float speedKmPerHour = location.gpsLocation.speed * 3.6;
248
249 length = snprintf(pMarker, lengthRemaining, "%.1lf,N,%.1lf,K,", speedKnots, speedKmPerHour);
250 }
251 else
252 {
253 length = snprintf(pMarker, lengthRemaining, ",N,,K,");
254 }
255
256 if (length < 0 || length >= lengthRemaining)
257 {
258 LOC_LOGE("NMEA Error in string formatting");
259 return;
260 }
261 pMarker += length;
262 lengthRemaining -= length;
263
264 if (!(location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG))
265 length = snprintf(pMarker, lengthRemaining, "%c", 'N'); // N means no fix
266 else if (LOC_POSITION_MODE_STANDALONE == loc_eng_data_p->adapter->getPositionMode().mode)
267 length = snprintf(pMarker, lengthRemaining, "%c", 'A'); // A means autonomous
268 else
269 length = snprintf(pMarker, lengthRemaining, "%c", 'D'); // D means differential
270
271 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
272 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
273
274 // ------------------
275 // ------$GPRMC------
276 // ------------------
277
278 pMarker = sentence;
279 lengthRemaining = sizeof(sentence);
280
281 length = snprintf(pMarker, lengthRemaining, "$GPRMC,%02d%02d%02d,A," ,
282 utcHours, utcMinutes, utcSeconds);
283
284 if (length < 0 || length >= lengthRemaining)
285 {
286 LOC_LOGE("NMEA Error in string formatting");
287 return;
288 }
289 pMarker += length;
290 lengthRemaining -= length;
291
292 if (location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG)
293 {
294 double latitude = location.gpsLocation.latitude;
295 double longitude = location.gpsLocation.longitude;
296 char latHemisphere;
297 char lonHemisphere;
298 double latMinutes;
299 double lonMinutes;
300
301 if (latitude > 0)
302 {
303 latHemisphere = 'N';
304 }
305 else
306 {
307 latHemisphere = 'S';
308 latitude *= -1.0;
309 }
310
311 if (longitude < 0)
312 {
313 lonHemisphere = 'W';
314 longitude *= -1.0;
315 }
316 else
317 {
318 lonHemisphere = 'E';
319 }
320
321 latMinutes = fmod(latitude * 60.0 , 60.0);
322 lonMinutes = fmod(longitude * 60.0 , 60.0);
323
324 length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
325 (uint8_t)floor(latitude), latMinutes, latHemisphere,
326 (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
327 }
328 else
329 {
330 length = snprintf(pMarker, lengthRemaining,",,,,");
331 }
332
333 if (length < 0 || length >= lengthRemaining)
334 {
335 LOC_LOGE("NMEA Error in string formatting");
336 return;
337 }
338 pMarker += length;
339 lengthRemaining -= length;
340
341 if (location.gpsLocation.flags & GPS_LOCATION_HAS_SPEED)
342 {
343 float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
344 length = snprintf(pMarker, lengthRemaining, "%.1lf,", speedKnots);
345 }
346 else
347 {
348 length = snprintf(pMarker, lengthRemaining, ",");
349 }
350
351 if (length < 0 || length >= lengthRemaining)
352 {
353 LOC_LOGE("NMEA Error in string formatting");
354 return;
355 }
356 pMarker += length;
357 lengthRemaining -= length;
358
359 if (location.gpsLocation.flags & GPS_LOCATION_HAS_BEARING)
360 {
361 length = snprintf(pMarker, lengthRemaining, "%.1lf,", location.gpsLocation.bearing);
362 }
363 else
364 {
365 length = snprintf(pMarker, lengthRemaining, ",");
366 }
367
368 if (length < 0 || length >= lengthRemaining)
369 {
370 LOC_LOGE("NMEA Error in string formatting");
371 return;
372 }
373 pMarker += length;
374 lengthRemaining -= length;
375
376 length = snprintf(pMarker, lengthRemaining, "%2.2d%2.2d%2.2d,",
377 utcDay, utcMonth, utcYear);
378
379 if (length < 0 || length >= lengthRemaining)
380 {
381 LOC_LOGE("NMEA Error in string formatting");
382 return;
383 }
384 pMarker += length;
385 lengthRemaining -= length;
386
387 if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
388 {
389 float magneticVariation = locationExtended.magneticDeviation;
390 char direction;
391 if (magneticVariation < 0.0)
392 {
393 direction = 'W';
394 magneticVariation *= -1.0;
395 }
396 else
397 {
398 direction = 'E';
399 }
400
401 length = snprintf(pMarker, lengthRemaining, "%.1lf,%c,",
402 magneticVariation, direction);
403 }
404 else
405 {
406 length = snprintf(pMarker, lengthRemaining, ",,");
407 }
408
409 if (length < 0 || length >= lengthRemaining)
410 {
411 LOC_LOGE("NMEA Error in string formatting");
412 return;
413 }
414 pMarker += length;
415 lengthRemaining -= length;
416
417 if (!(location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG))
418 length = snprintf(pMarker, lengthRemaining, "%c", 'N'); // N means no fix
419 else if (LOC_POSITION_MODE_STANDALONE == loc_eng_data_p->adapter->getPositionMode().mode)
420 length = snprintf(pMarker, lengthRemaining, "%c", 'A'); // A means autonomous
421 else
422 length = snprintf(pMarker, lengthRemaining, "%c", 'D'); // D means differential
423
424 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
425 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
426
427 // ------------------
428 // ------$GPGGA------
429 // ------------------
430
431 pMarker = sentence;
432 lengthRemaining = sizeof(sentence);
433
434 length = snprintf(pMarker, lengthRemaining, "$GPGGA,%02d%02d%02d," ,
435 utcHours, utcMinutes, utcSeconds);
436
437 if (length < 0 || length >= lengthRemaining)
438 {
439 LOC_LOGE("NMEA Error in string formatting");
440 return;
441 }
442 pMarker += length;
443 lengthRemaining -= length;
444
445 if (location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG)
446 {
447 double latitude = location.gpsLocation.latitude;
448 double longitude = location.gpsLocation.longitude;
449 char latHemisphere;
450 char lonHemisphere;
451 double latMinutes;
452 double lonMinutes;
453
454 if (latitude > 0)
455 {
456 latHemisphere = 'N';
457 }
458 else
459 {
460 latHemisphere = 'S';
461 latitude *= -1.0;
462 }
463
464 if (longitude < 0)
465 {
466 lonHemisphere = 'W';
467 longitude *= -1.0;
468 }
469 else
470 {
471 lonHemisphere = 'E';
472 }
473
474 latMinutes = fmod(latitude * 60.0 , 60.0);
475 lonMinutes = fmod(longitude * 60.0 , 60.0);
476
477 length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
478 (uint8_t)floor(latitude), latMinutes, latHemisphere,
479 (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
480 }
481 else
482 {
483 length = snprintf(pMarker, lengthRemaining,",,,,");
484 }
485
486 if (length < 0 || length >= lengthRemaining)
487 {
488 LOC_LOGE("NMEA Error in string formatting");
489 return;
490 }
491 pMarker += length;
492 lengthRemaining -= length;
493
494 char gpsQuality;
495 if (!(location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG))
496 gpsQuality = '0'; // 0 means no fix
497 else if (LOC_POSITION_MODE_STANDALONE == loc_eng_data_p->adapter->getPositionMode().mode)
498 gpsQuality = '1'; // 1 means GPS fix
499 else
500 gpsQuality = '2'; // 2 means DGPS fix
501
502 if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
503 { // dop is in locationExtended, (QMI)
504 length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,",
505 gpsQuality, svUsedCount, locationExtended.hdop);
506 }
507 else if (loc_eng_data_p->pdop > 0 && loc_eng_data_p->hdop > 0 && loc_eng_data_p->vdop > 0)
508 { // dop was cached from sv report (RPC)
509 length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,",
510 gpsQuality, svUsedCount, loc_eng_data_p->hdop);
511 }
512 else
513 { // no hdop
514 length = snprintf(pMarker, lengthRemaining, "%c,%02d,,",
515 gpsQuality, svUsedCount);
516 }
517
518 if (length < 0 || length >= lengthRemaining)
519 {
520 LOC_LOGE("NMEA Error in string formatting");
521 return;
522 }
523 pMarker += length;
524 lengthRemaining -= length;
525
526 if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)
527 {
528 length = snprintf(pMarker, lengthRemaining, "%.1lf,M,",
529 locationExtended.altitudeMeanSeaLevel);
530 }
531 else
532 {
533 length = snprintf(pMarker, lengthRemaining,",,");
534 }
535
536 if (length < 0 || length >= lengthRemaining)
537 {
538 LOC_LOGE("NMEA Error in string formatting");
539 return;
540 }
541 pMarker += length;
542 lengthRemaining -= length;
543
544 if ((location.gpsLocation.flags & GPS_LOCATION_HAS_ALTITUDE) &&
545 (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL))
546 {
547 length = snprintf(pMarker, lengthRemaining, "%.1lf,M,,",
548 location.gpsLocation.altitude - locationExtended.altitudeMeanSeaLevel);
549 }
550 else
551 {
552 length = snprintf(pMarker, lengthRemaining,",,,");
553 }
554
555 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
556 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
557
558 }
559 //Send blank NMEA reports for non-final fixes
560 else {
561 strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,", sizeof(sentence));
562 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
563 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
564
565 strlcpy(sentence, "$GPVTG,,T,,M,,N,,K,N", sizeof(sentence));
566 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
567 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
568
569 strlcpy(sentence, "$GPRMC,,V,,,,,,,,,,N", sizeof(sentence));
570 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
571 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
572
573 strlcpy(sentence, "$GPGGA,,,,,,0,,,,,,,,", sizeof(sentence));
574 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
575 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
576 }
577 // clear the dop cache so they can't be used again
578 loc_eng_data_p->pdop = 0;
579 loc_eng_data_p->hdop = 0;
580 loc_eng_data_p->vdop = 0;
581
582 EXIT_LOG(%d, 0);
583 }
584
585
586
587 /*===========================================================================
588 FUNCTION loc_eng_nmea_generate_sv
589
590 DESCRIPTION
591 Generate NMEA sentences generated based on sv report
592
593 DEPENDENCIES
594 NONE
595
596 RETURN VALUE
597 0
598
599 SIDE EFFECTS
600 N/A
601
602 ===========================================================================*/
loc_eng_nmea_generate_sv(loc_eng_data_s_type * loc_eng_data_p,const GpsSvStatus & svStatus,const GpsLocationExtended & locationExtended)603 void loc_eng_nmea_generate_sv(loc_eng_data_s_type *loc_eng_data_p,
604 const GpsSvStatus &svStatus, const GpsLocationExtended &locationExtended)
605 {
606 ENTRY_LOG();
607
608 char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
609 char* pMarker = sentence;
610 int lengthRemaining = sizeof(sentence);
611 int length = 0;
612 int svCount = svStatus.num_svs;
613 int sentenceCount = 0;
614 int sentenceNumber = 1;
615 int svNumber = 1;
616 int gpsCount = 0;
617 int glnCount = 0;
618
619 //Count GPS SVs for saparating GPS from GLONASS and throw others
620
621 for(svNumber=1; svNumber <= svCount; svNumber++) {
622 if( (svStatus.sv_list[svNumber-1].prn >= GPS_PRN_START)&&
623 (svStatus.sv_list[svNumber-1].prn <= GPS_PRN_END) )
624 {
625 gpsCount++;
626 }
627 else if( (svStatus.sv_list[svNumber-1].prn >= GLONASS_PRN_START) &&
628 (svStatus.sv_list[svNumber-1].prn <= GLONASS_PRN_END) )
629 {
630 glnCount++;
631 }
632 }
633
634 // ------------------
635 // ------$GPGSV------
636 // ------------------
637
638 if (gpsCount <= 0)
639 {
640 // no svs in view, so just send a blank $GPGSV sentence
641 strlcpy(sentence, "$GPGSV,1,1,0,", sizeof(sentence));
642 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
643 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
644 }
645 else
646 {
647 svNumber = 1;
648 sentenceNumber = 1;
649 sentenceCount = gpsCount/4 + (gpsCount % 4 != 0);
650
651 while (sentenceNumber <= sentenceCount)
652 {
653 pMarker = sentence;
654 lengthRemaining = sizeof(sentence);
655
656 length = snprintf(pMarker, lengthRemaining, "$GPGSV,%d,%d,%02d",
657 sentenceCount, sentenceNumber, gpsCount);
658
659 if (length < 0 || length >= lengthRemaining)
660 {
661 LOC_LOGE("NMEA Error in string formatting");
662 return;
663 }
664 pMarker += length;
665 lengthRemaining -= length;
666
667 for (int i=0; (svNumber <= svCount) && (i < 4); svNumber++)
668 {
669 if( (svStatus.sv_list[svNumber-1].prn >= GPS_PRN_START) &&
670 (svStatus.sv_list[svNumber-1].prn <= GPS_PRN_END) )
671 {
672 length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,",
673 svStatus.sv_list[svNumber-1].prn,
674 (int)(0.5 + svStatus.sv_list[svNumber-1].elevation), //float to int
675 (int)(0.5 + svStatus.sv_list[svNumber-1].azimuth)); //float to int
676
677 if (length < 0 || length >= lengthRemaining)
678 {
679 LOC_LOGE("NMEA Error in string formatting");
680 return;
681 }
682 pMarker += length;
683 lengthRemaining -= length;
684
685 if (svStatus.sv_list[svNumber-1].snr > 0)
686 {
687 length = snprintf(pMarker, lengthRemaining,"%02d",
688 (int)(0.5 + svStatus.sv_list[svNumber-1].snr)); //float to int
689
690 if (length < 0 || length >= lengthRemaining)
691 {
692 LOC_LOGE("NMEA Error in string formatting");
693 return;
694 }
695 pMarker += length;
696 lengthRemaining -= length;
697 }
698
699 i++;
700 }
701
702 }
703
704 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
705 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
706 sentenceNumber++;
707
708 } //while
709
710 } //if
711
712 // ------------------
713 // ------$GLGSV------
714 // ------------------
715
716 if (glnCount <= 0)
717 {
718 // no svs in view, so just send a blank $GLGSV sentence
719 strlcpy(sentence, "$GLGSV,1,1,0,", sizeof(sentence));
720 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
721 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
722 }
723 else
724 {
725 svNumber = 1;
726 sentenceNumber = 1;
727 sentenceCount = glnCount/4 + (glnCount % 4 != 0);
728
729 while (sentenceNumber <= sentenceCount)
730 {
731 pMarker = sentence;
732 lengthRemaining = sizeof(sentence);
733
734 length = snprintf(pMarker, lengthRemaining, "$GLGSV,%d,%d,%02d",
735 sentenceCount, sentenceNumber, glnCount);
736
737 if (length < 0 || length >= lengthRemaining)
738 {
739 LOC_LOGE("NMEA Error in string formatting");
740 return;
741 }
742 pMarker += length;
743 lengthRemaining -= length;
744
745 for (int i=0; (svNumber <= svCount) && (i < 4); svNumber++)
746 {
747 if( (svStatus.sv_list[svNumber-1].prn >= GLONASS_PRN_START) &&
748 (svStatus.sv_list[svNumber-1].prn <= GLONASS_PRN_END) ) {
749
750 length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,",
751 svStatus.sv_list[svNumber-1].prn,
752 (int)(0.5 + svStatus.sv_list[svNumber-1].elevation), //float to int
753 (int)(0.5 + svStatus.sv_list[svNumber-1].azimuth)); //float to int
754
755 if (length < 0 || length >= lengthRemaining)
756 {
757 LOC_LOGE("NMEA Error in string formatting");
758 return;
759 }
760 pMarker += length;
761 lengthRemaining -= length;
762
763 if (svStatus.sv_list[svNumber-1].snr > 0)
764 {
765 length = snprintf(pMarker, lengthRemaining,"%02d",
766 (int)(0.5 + svStatus.sv_list[svNumber-1].snr)); //float to int
767
768 if (length < 0 || length >= lengthRemaining)
769 {
770 LOC_LOGE("NMEA Error in string formatting");
771 return;
772 }
773 pMarker += length;
774 lengthRemaining -= length;
775 }
776
777 i++;
778 }
779
780 }
781
782 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
783 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
784 sentenceNumber++;
785
786 } //while
787
788 }//if
789
790 if (svStatus.used_in_fix_mask == 0)
791 { // No sv used, so there will be no position report, so send
792 // blank NMEA sentences
793 strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,", sizeof(sentence));
794 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
795 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
796
797 strlcpy(sentence, "$GPVTG,,T,,M,,N,,K,N", sizeof(sentence));
798 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
799 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
800
801 strlcpy(sentence, "$GPRMC,,V,,,,,,,,,,N", sizeof(sentence));
802 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
803 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
804
805 strlcpy(sentence, "$GPGGA,,,,,,0,,,,,,,,", sizeof(sentence));
806 length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
807 loc_eng_nmea_send(sentence, length, loc_eng_data_p);
808 }
809 else
810 { // cache the used in fix mask, as it will be needed to send $GPGSA
811 // during the position report
812 loc_eng_data_p->sv_used_mask = svStatus.used_in_fix_mask;
813
814 // For RPC, the DOP are sent during sv report, so cache them
815 // now to be sent during position report.
816 // For QMI, the DOP will be in position report.
817 if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
818 {
819 loc_eng_data_p->pdop = locationExtended.pdop;
820 loc_eng_data_p->hdop = locationExtended.hdop;
821 loc_eng_data_p->vdop = locationExtended.vdop;
822 }
823 else
824 {
825 loc_eng_data_p->pdop = 0;
826 loc_eng_data_p->hdop = 0;
827 loc_eng_data_p->vdop = 0;
828 }
829
830 }
831
832 EXIT_LOG(%d, 0);
833 }
834