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