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