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