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