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 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/*=========================================================================== 65FUNCTION loc_eng_nmea_put_checksum 66 67DESCRIPTION 68 Generate NMEA sentences generated based on position report 69 70DEPENDENCIES 71 NONE 72 73RETURN VALUE 74 Total length of the nmea sentence 75 76SIDE EFFECTS 77 N/A 78 79===========================================================================*/ 80int 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/*=========================================================================== 97FUNCTION loc_eng_nmea_generate_pos 98 99DESCRIPTION 100 Generate NMEA sentences generated based on position report 101 102DEPENDENCIES 103 NONE 104 105RETURN VALUE 106 0 107 108SIDE EFFECTS 109 N/A 110 111===========================================================================*/ 112void 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/*=========================================================================== 584FUNCTION loc_eng_nmea_generate_sv 585 586DESCRIPTION 587 Generate NMEA sentences generated based on sv report 588 589DEPENDENCIES 590 NONE 591 592RETURN VALUE 593 0 594 595SIDE EFFECTS 596 N/A 597 598===========================================================================*/ 599void 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