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