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