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 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/*=========================================================================== 588FUNCTION loc_eng_nmea_generate_sv 589 590DESCRIPTION 591 Generate NMEA sentences generated based on sv report 592 593DEPENDENCIES 594 NONE 595 596RETURN VALUE 597 0 598 599SIDE EFFECTS 600 N/A 601 602===========================================================================*/ 603void 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