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