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/*=========================================================================== 39FUNCTION loc_eng_nmea_send 40 41DESCRIPTION 42 send out NMEA sentence 43 44DEPENDENCIES 45 NONE 46 47RETURN VALUE 48 Total length of the nmea sentence 49 50SIDE EFFECTS 51 N/A 52 53===========================================================================*/ 54void 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/*=========================================================================== 64FUNCTION loc_eng_nmea_put_checksum 65 66DESCRIPTION 67 Generate NMEA sentences generated based on position report 68 69DEPENDENCIES 70 NONE 71 72RETURN VALUE 73 Total length of the nmea sentence 74 75SIDE EFFECTS 76 N/A 77 78===========================================================================*/ 79int 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/*=========================================================================== 96FUNCTION loc_eng_nmea_generate_pos 97 98DESCRIPTION 99 Generate NMEA sentences generated based on position report 100 101DEPENDENCIES 102 NONE 103 104RETURN VALUE 105 0 106 107SIDE EFFECTS 108 N/A 109 110===========================================================================*/ 111void 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/*=========================================================================== 583FUNCTION loc_eng_nmea_generate_sv 584 585DESCRIPTION 586 Generate NMEA sentences generated based on sv report 587 588DEPENDENCIES 589 NONE 590 591RETURN VALUE 592 0 593 594SIDE EFFECTS 595 N/A 596 597===========================================================================*/ 598void 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