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