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