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
33#include <loc_eng.h>
34#include <loc_eng_nmea.h>
35#include <math.h>
36#include "log_util.h"
37
38/*===========================================================================
39FUNCTION    loc_eng_nmea_send
40
41DESCRIPTION
42   send out NMEA sentence
43
44DEPENDENCIES
45   NONE
46
47RETURN VALUE
48   Total length of the nmea sentence
49
50SIDE EFFECTS
51   N/A
52
53===========================================================================*/
54void loc_eng_nmea_send(char *pNmea, int length, loc_eng_data_s_type *loc_eng_data_p)
55{
56    struct timeval tv;
57    gettimeofday(&tv, (struct timezone *) NULL);
58    int64_t now = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
59    CALLBACK_LOG_CALLFLOW("nmea_cb", %p, pNmea);
60    loc_eng_data_p->nmea_cb(now, pNmea, length);
61    LOC_LOGD("NMEA <%s", pNmea);
62}
63
64/*===========================================================================
65FUNCTION    loc_eng_nmea_put_checksum
66
67DESCRIPTION
68   Generate NMEA sentences generated based on position report
69
70DEPENDENCIES
71   NONE
72
73RETURN VALUE
74   Total length of the nmea sentence
75
76SIDE EFFECTS
77   N/A
78
79===========================================================================*/
80int loc_eng_nmea_put_checksum(char *pNmea, int maxSize)
81{
82    uint8_t checksum = 0;
83    int length = 0;
84
85    pNmea++; //skip the $
86    while (*pNmea != '\0')
87    {
88        checksum ^= *pNmea++;
89        length++;
90    }
91
92    int checksumLength = snprintf(pNmea,(maxSize-length-1),"*%02X\r\n", checksum);
93    return (length + checksumLength);
94}
95
96/*===========================================================================
97FUNCTION    loc_eng_nmea_generate_pos
98
99DESCRIPTION
100   Generate NMEA sentences generated based on position report
101
102DEPENDENCIES
103   NONE
104
105RETURN VALUE
106   0
107
108SIDE EFFECTS
109   N/A
110
111===========================================================================*/
112void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
113                               const UlpLocation &location,
114                               const GpsLocationExtended &locationExtended,
115                               unsigned char generate_nmea)
116{
117    ENTRY_LOG();
118
119    char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
120    char* pMarker = sentence;
121    int lengthRemaining = sizeof(sentence);
122    int length = 0;
123
124    time_t utcTime(location.gpsLocation.timestamp/1000);
125    tm * pTm = gmtime(&utcTime);
126    int utcYear = pTm->tm_year % 100; // 2 digit year
127    int utcMonth = pTm->tm_mon + 1; // tm_mon starts at zero
128    int utcDay = pTm->tm_mday;
129    int utcHours = pTm->tm_hour;
130    int utcMinutes = pTm->tm_min;
131    int utcSeconds = pTm->tm_sec;
132
133    if (generate_nmea) {
134        // ------------------
135        // ------$GPGSA------
136        // ------------------
137
138        uint32_t svUsedCount = 0;
139        uint32_t svUsedList[32] = {0};
140        uint32_t mask = loc_eng_data_p->sv_used_mask;
141        for (uint8_t i = 1; mask > 0 && svUsedCount < 32; i++)
142        {
143            if (mask & 1)
144                svUsedList[svUsedCount++] = i;
145            mask = mask >> 1;
146        }
147        // clear the cache so they can't be used again
148        loc_eng_data_p->sv_used_mask = 0;
149
150        char fixType;
151        if (svUsedCount == 0)
152            fixType = '1'; // no fix
153        else if (svUsedCount <= 3)
154            fixType = '2'; // 2D fix
155        else
156            fixType = '3'; // 3D fix
157
158        length = snprintf(pMarker, lengthRemaining, "$GPGSA,A,%c,", fixType);
159
160        if (length < 0 || length >= lengthRemaining)
161        {
162            LOC_LOGE("NMEA Error in string formatting");
163            return;
164        }
165        pMarker += length;
166        lengthRemaining -= length;
167
168        for (uint8_t i = 0; i < 12; i++) // only the first 12 sv go in sentence
169        {
170            if (i < svUsedCount)
171                length = snprintf(pMarker, lengthRemaining, "%02d,", svUsedList[i]);
172            else
173                length = snprintf(pMarker, lengthRemaining, ",");
174
175            if (length < 0 || length >= lengthRemaining)
176            {
177                LOC_LOGE("NMEA Error in string formatting");
178                return;
179            }
180            pMarker += length;
181            lengthRemaining -= length;
182        }
183
184        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
185        {   // dop is in locationExtended, (QMI)
186            length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
187                              locationExtended.pdop,
188                              locationExtended.hdop,
189                              locationExtended.vdop);
190        }
191        else if (loc_eng_data_p->pdop > 0 && loc_eng_data_p->hdop > 0 && loc_eng_data_p->vdop > 0)
192        {   // dop was cached from sv report (RPC)
193            length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
194                              loc_eng_data_p->pdop,
195                              loc_eng_data_p->hdop,
196                              loc_eng_data_p->vdop);
197        }
198        else
199        {   // no dop
200            length = snprintf(pMarker, lengthRemaining, ",,");
201        }
202
203        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
204        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
205
206        // ------------------
207        // ------$GPVTG------
208        // ------------------
209
210        pMarker = sentence;
211        lengthRemaining = sizeof(sentence);
212
213        if (location.gpsLocation.flags & GPS_LOCATION_HAS_BEARING)
214        {
215            float magTrack = location.gpsLocation.bearing;
216            if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
217            {
218                float magTrack = location.gpsLocation.bearing - locationExtended.magneticDeviation;
219                if (magTrack < 0.0)
220                    magTrack += 360.0;
221                else if (magTrack > 360.0)
222                    magTrack -= 360.0;
223            }
224
225            length = snprintf(pMarker, lengthRemaining, "$GPVTG,%.1lf,T,%.1lf,M,", location.gpsLocation.bearing, magTrack);
226        }
227        else
228        {
229            length = snprintf(pMarker, lengthRemaining, "$GPVTG,,T,,M,");
230        }
231
232        if (length < 0 || length >= lengthRemaining)
233        {
234            LOC_LOGE("NMEA Error in string formatting");
235            return;
236        }
237        pMarker += length;
238        lengthRemaining -= length;
239
240        if (location.gpsLocation.flags & GPS_LOCATION_HAS_SPEED)
241        {
242            float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
243            float speedKmPerHour = location.gpsLocation.speed * 3.6;
244
245            length = snprintf(pMarker, lengthRemaining, "%.1lf,N,%.1lf,K,", speedKnots, speedKmPerHour);
246        }
247        else
248        {
249            length = snprintf(pMarker, lengthRemaining, ",N,,K,");
250        }
251
252        if (length < 0 || length >= lengthRemaining)
253        {
254            LOC_LOGE("NMEA Error in string formatting");
255            return;
256        }
257        pMarker += length;
258        lengthRemaining -= length;
259
260        if (!(location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG))
261            length = snprintf(pMarker, lengthRemaining, "%c", 'N'); // N means no fix
262        else if (LOC_POSITION_MODE_STANDALONE == loc_eng_data_p->adapter->getPositionMode().mode)
263            length = snprintf(pMarker, lengthRemaining, "%c", 'A'); // A means autonomous
264        else
265            length = snprintf(pMarker, lengthRemaining, "%c", 'D'); // D means differential
266
267        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
268        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
269
270        // ------------------
271        // ------$GPRMC------
272        // ------------------
273
274        pMarker = sentence;
275        lengthRemaining = sizeof(sentence);
276
277        length = snprintf(pMarker, lengthRemaining, "$GPRMC,%02d%02d%02d,A," ,
278                          utcHours, utcMinutes, utcSeconds);
279
280        if (length < 0 || length >= lengthRemaining)
281        {
282            LOC_LOGE("NMEA Error in string formatting");
283            return;
284        }
285        pMarker += length;
286        lengthRemaining -= length;
287
288        if (location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG)
289        {
290            double latitude = location.gpsLocation.latitude;
291            double longitude = location.gpsLocation.longitude;
292            char latHemisphere;
293            char lonHemisphere;
294            double latMinutes;
295            double lonMinutes;
296
297            if (latitude > 0)
298            {
299                latHemisphere = 'N';
300            }
301            else
302            {
303                latHemisphere = 'S';
304                latitude *= -1.0;
305            }
306
307            if (longitude < 0)
308            {
309                lonHemisphere = 'W';
310                longitude *= -1.0;
311            }
312            else
313            {
314                lonHemisphere = 'E';
315            }
316
317            latMinutes = fmod(latitude * 60.0 , 60.0);
318            lonMinutes = fmod(longitude * 60.0 , 60.0);
319
320            length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
321                              (uint8_t)floor(latitude), latMinutes, latHemisphere,
322                              (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
323        }
324        else
325        {
326            length = snprintf(pMarker, lengthRemaining,",,,,");
327        }
328
329        if (length < 0 || length >= lengthRemaining)
330        {
331            LOC_LOGE("NMEA Error in string formatting");
332            return;
333        }
334        pMarker += length;
335        lengthRemaining -= length;
336
337        if (location.gpsLocation.flags & GPS_LOCATION_HAS_SPEED)
338        {
339            float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
340            length = snprintf(pMarker, lengthRemaining, "%.1lf,", speedKnots);
341        }
342        else
343        {
344            length = snprintf(pMarker, lengthRemaining, ",");
345        }
346
347        if (length < 0 || length >= lengthRemaining)
348        {
349            LOC_LOGE("NMEA Error in string formatting");
350            return;
351        }
352        pMarker += length;
353        lengthRemaining -= length;
354
355        if (location.gpsLocation.flags & GPS_LOCATION_HAS_BEARING)
356        {
357            length = snprintf(pMarker, lengthRemaining, "%.1lf,", location.gpsLocation.bearing);
358        }
359        else
360        {
361            length = snprintf(pMarker, lengthRemaining, ",");
362        }
363
364        if (length < 0 || length >= lengthRemaining)
365        {
366            LOC_LOGE("NMEA Error in string formatting");
367            return;
368        }
369        pMarker += length;
370        lengthRemaining -= length;
371
372        length = snprintf(pMarker, lengthRemaining, "%2.2d%2.2d%2.2d,",
373                          utcDay, utcMonth, utcYear);
374
375        if (length < 0 || length >= lengthRemaining)
376        {
377            LOC_LOGE("NMEA Error in string formatting");
378            return;
379        }
380        pMarker += length;
381        lengthRemaining -= length;
382
383        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
384        {
385            float magneticVariation = locationExtended.magneticDeviation;
386            char direction;
387            if (magneticVariation < 0.0)
388            {
389                direction = 'W';
390                magneticVariation *= -1.0;
391            }
392            else
393            {
394                direction = 'E';
395            }
396
397            length = snprintf(pMarker, lengthRemaining, "%.1lf,%c,",
398                              magneticVariation, direction);
399        }
400        else
401        {
402            length = snprintf(pMarker, lengthRemaining, ",,");
403        }
404
405        if (length < 0 || length >= lengthRemaining)
406        {
407            LOC_LOGE("NMEA Error in string formatting");
408            return;
409        }
410        pMarker += length;
411        lengthRemaining -= length;
412
413        if (!(location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG))
414            length = snprintf(pMarker, lengthRemaining, "%c", 'N'); // N means no fix
415        else if (LOC_POSITION_MODE_STANDALONE == loc_eng_data_p->adapter->getPositionMode().mode)
416            length = snprintf(pMarker, lengthRemaining, "%c", 'A'); // A means autonomous
417        else
418            length = snprintf(pMarker, lengthRemaining, "%c", 'D'); // D means differential
419
420        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
421        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
422
423        // ------------------
424        // ------$GPGGA------
425        // ------------------
426
427        pMarker = sentence;
428        lengthRemaining = sizeof(sentence);
429
430        length = snprintf(pMarker, lengthRemaining, "$GPGGA,%02d%02d%02d," ,
431                          utcHours, utcMinutes, utcSeconds);
432
433        if (length < 0 || length >= lengthRemaining)
434        {
435            LOC_LOGE("NMEA Error in string formatting");
436            return;
437        }
438        pMarker += length;
439        lengthRemaining -= length;
440
441        if (location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG)
442        {
443            double latitude = location.gpsLocation.latitude;
444            double longitude = location.gpsLocation.longitude;
445            char latHemisphere;
446            char lonHemisphere;
447            double latMinutes;
448            double lonMinutes;
449
450            if (latitude > 0)
451            {
452                latHemisphere = 'N';
453            }
454            else
455            {
456                latHemisphere = 'S';
457                latitude *= -1.0;
458            }
459
460            if (longitude < 0)
461            {
462                lonHemisphere = 'W';
463                longitude *= -1.0;
464            }
465            else
466            {
467                lonHemisphere = 'E';
468            }
469
470            latMinutes = fmod(latitude * 60.0 , 60.0);
471            lonMinutes = fmod(longitude * 60.0 , 60.0);
472
473            length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
474                              (uint8_t)floor(latitude), latMinutes, latHemisphere,
475                              (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
476        }
477        else
478        {
479            length = snprintf(pMarker, lengthRemaining,",,,,");
480        }
481
482        if (length < 0 || length >= lengthRemaining)
483        {
484            LOC_LOGE("NMEA Error in string formatting");
485            return;
486        }
487        pMarker += length;
488        lengthRemaining -= length;
489
490        char gpsQuality;
491        if (!(location.gpsLocation.flags & GPS_LOCATION_HAS_LAT_LONG))
492            gpsQuality = '0'; // 0 means no fix
493        else if (LOC_POSITION_MODE_STANDALONE == loc_eng_data_p->adapter->getPositionMode().mode)
494            gpsQuality = '1'; // 1 means GPS fix
495        else
496            gpsQuality = '2'; // 2 means DGPS fix
497
498        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
499        {   // dop is in locationExtended, (QMI)
500            length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,",
501                              gpsQuality, svUsedCount, locationExtended.hdop);
502        }
503        else if (loc_eng_data_p->pdop > 0 && loc_eng_data_p->hdop > 0 && loc_eng_data_p->vdop > 0)
504        {   // dop was cached from sv report (RPC)
505            length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,",
506                              gpsQuality, svUsedCount, loc_eng_data_p->hdop);
507        }
508        else
509        {   // no hdop
510            length = snprintf(pMarker, lengthRemaining, "%c,%02d,,",
511                              gpsQuality, svUsedCount);
512        }
513
514        if (length < 0 || length >= lengthRemaining)
515        {
516            LOC_LOGE("NMEA Error in string formatting");
517            return;
518        }
519        pMarker += length;
520        lengthRemaining -= length;
521
522        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)
523        {
524            length = snprintf(pMarker, lengthRemaining, "%.1lf,M,",
525                              locationExtended.altitudeMeanSeaLevel);
526        }
527        else
528        {
529            length = snprintf(pMarker, lengthRemaining,",,");
530        }
531
532        if (length < 0 || length >= lengthRemaining)
533        {
534            LOC_LOGE("NMEA Error in string formatting");
535            return;
536        }
537        pMarker += length;
538        lengthRemaining -= length;
539
540        if ((location.gpsLocation.flags & GPS_LOCATION_HAS_ALTITUDE) &&
541            (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL))
542        {
543            length = snprintf(pMarker, lengthRemaining, "%.1lf,M,,",
544                              location.gpsLocation.altitude - locationExtended.altitudeMeanSeaLevel);
545        }
546        else
547        {
548            length = snprintf(pMarker, lengthRemaining,",,,");
549        }
550
551        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
552        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
553
554    }
555    //Send blank NMEA reports for non-final fixes
556    else {
557        strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,", sizeof(sentence));
558        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
559        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
560
561        strlcpy(sentence, "$GPVTG,,T,,M,,N,,K,N", 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, "$GPRMC,,V,,,,,,,,,,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, "$GPGGA,,,,,,0,,,,,,,,", 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    // clear the dop cache so they can't be used again
574    loc_eng_data_p->pdop = 0;
575    loc_eng_data_p->hdop = 0;
576    loc_eng_data_p->vdop = 0;
577
578    EXIT_LOG(%d, 0);
579}
580
581
582
583/*===========================================================================
584FUNCTION    loc_eng_nmea_generate_sv
585
586DESCRIPTION
587   Generate NMEA sentences generated based on sv report
588
589DEPENDENCIES
590   NONE
591
592RETURN VALUE
593   0
594
595SIDE EFFECTS
596   N/A
597
598===========================================================================*/
599void loc_eng_nmea_generate_sv(loc_eng_data_s_type *loc_eng_data_p,
600                              const GpsSvStatus &svStatus, const GpsLocationExtended &locationExtended)
601{
602    ENTRY_LOG();
603
604    char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
605    char* pMarker = sentence;
606    int lengthRemaining = sizeof(sentence);
607    int length = 0;
608
609    // ------------------
610    // ------$GPGSV------
611    // ------------------
612
613    if (svStatus.num_svs <= 0)
614    {
615        // no svs in view, so just send a blank $GPGSV sentence
616        strlcpy(sentence, "$GPGSV,1,1,0,", sizeof(sentence));
617        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
618        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
619    }
620    else
621    {
622        int svCount = svStatus.num_svs;
623        int sentenceCount = svCount / 4;
624        if (svStatus.num_svs % 4)
625            sentenceCount++;
626        int sentenceNumber = 1;
627        int svNumber = 1;
628
629        while (sentenceNumber <= sentenceCount)
630        {
631            pMarker = sentence;
632            lengthRemaining = sizeof(sentence);
633
634            length = snprintf(pMarker, lengthRemaining, "$GPGSV,%d,%d,%02d",
635                          sentenceCount, sentenceNumber, svCount);
636
637            if (length < 0 || length >= lengthRemaining)
638            {
639                LOC_LOGE("NMEA Error in string formatting");
640                return;
641            }
642            pMarker += length;
643            lengthRemaining -= length;
644
645            for (int i=0; (svNumber <= svCount) && (i < 4); i++, svNumber++)
646            {
647                length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,",
648                                  svStatus.sv_list[svNumber-1].prn,
649                                  (int)(0.5 + svStatus.sv_list[svNumber-1].elevation), //float to int
650                                  (int)(0.5 + svStatus.sv_list[svNumber-1].azimuth)); //float to int
651
652                if (length < 0 || length >= lengthRemaining)
653                {
654                    LOC_LOGE("NMEA Error in string formatting");
655                    return;
656                }
657                pMarker += length;
658                lengthRemaining -= length;
659
660                if (svStatus.sv_list[svNumber-1].snr > 0)
661                {
662                    length = snprintf(pMarker, lengthRemaining,"%02d",
663                                     (int)(0.5 + svStatus.sv_list[svNumber-1].snr)); //float to int
664
665                    if (length < 0 || length >= lengthRemaining)
666                    {
667                        LOC_LOGE("NMEA Error in string formatting");
668                        return;
669                    }
670                    pMarker += length;
671                    lengthRemaining -= length;
672                }
673            }
674
675            length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
676            loc_eng_nmea_send(sentence, length, loc_eng_data_p);
677            sentenceNumber++;
678
679        }
680    }
681
682    if (svStatus.used_in_fix_mask == 0)
683    {   // No sv used, so there will be no position report, so send
684        // blank NMEA sentences
685        strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,", sizeof(sentence));
686        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
687        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
688
689        strlcpy(sentence, "$GPVTG,,T,,M,,N,,K,N", sizeof(sentence));
690        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
691        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
692
693        strlcpy(sentence, "$GPRMC,,V,,,,,,,,,,N", sizeof(sentence));
694        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
695        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
696
697        strlcpy(sentence, "$GPGGA,,,,,,0,,,,,,,,", sizeof(sentence));
698        length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
699        loc_eng_nmea_send(sentence, length, loc_eng_data_p);
700    }
701    else
702    {   // cache the used in fix mask, as it will be needed to send $GPGSA
703        // during the position report
704        loc_eng_data_p->sv_used_mask = svStatus.used_in_fix_mask;
705
706        // For RPC, the DOP are sent during sv report, so cache them
707        // now to be sent during position report.
708        // For QMI, the DOP will be in position report.
709        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
710        {
711            loc_eng_data_p->pdop = locationExtended.pdop;
712            loc_eng_data_p->hdop = locationExtended.hdop;
713            loc_eng_data_p->vdop = locationExtended.vdop;
714        }
715        else
716        {
717            loc_eng_data_p->pdop = 0;
718            loc_eng_data_p->hdop = 0;
719            loc_eng_data_p->vdop = 0;
720        }
721
722    }
723
724    EXIT_LOG(%d, 0);
725}
726