00001 #include <iostream>
00002 #include "GPS.h"
00003
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include <fcntl.h>
00007
00008 #include <stdlib.h>
00009 #include <termios.h>
00010 #include <unistd.h>
00011 #include <errno.h>
00012 #include <sys/ioctl.h>
00013 #include <math.h>
00014 #include <fcntl.h>
00015
00016 using std::cerr;
00017 using std::cout;
00018 using std::endl;
00019
00020
00021 double GPS::invalid;
00022
00033 GPS::GPS(void) {
00034 initVars();
00035 }
00036
00047 GPS::GPS(const char* serial_dev, int nowait)
00048 {
00049 initVars();
00050
00051 if (nowait) {
00052 gps_fd = open(serial_dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
00053 } else {
00054 gps_fd = open(serial_dev, O_RDWR | O_NOCTTY);
00055 }
00056
00057 if (gps_fd < 0)
00058 {
00059 std::cerr << "opening serial port '" << serial_dev << "' failed : " << strerror(errno) << std::endl;
00060 exit(EXIT_FAILURE);
00061 }
00062
00063
00064 struct termios newtio;
00065 bzero(&newtio, sizeof(newtio));
00066 newtio.c_cflag = CS8 | B9600 | CRTSCTS | CLOCAL | CREAD;
00067 newtio.c_iflag = IGNPAR;
00068 newtio.c_oflag = 0;
00069 newtio.c_lflag = ICANON;
00070 newtio.c_cc[VINTR] = 0;
00071 newtio.c_cc[VQUIT] = 0;
00072 newtio.c_cc[VERASE] = 0;
00073 newtio.c_cc[VKILL] = 0;
00074 newtio.c_cc[VEOF] = 0;
00075 newtio.c_cc[VTIME] = 0;
00076 newtio.c_cc[VMIN] = 1;
00077 newtio.c_cc[VSWTC] = 0;
00078 newtio.c_cc[VSTART] = 0;
00079 newtio.c_cc[VSTOP] = 0;
00080 newtio.c_cc[VSUSP] = 0;
00081 newtio.c_cc[VEOL] = 0;
00082 newtio.c_cc[VREPRINT] = 0;
00083 newtio.c_cc[VDISCARD] = 0;
00084 newtio.c_cc[VWERASE] = 0;
00085 newtio.c_cc[VLNEXT] = 0;
00086 newtio.c_cc[VEOL2] = 0;
00087
00088
00089 tcflush(gps_fd, TCIOFLUSH);
00090
00091 int result = tcsetattr(gps_fd,TCSANOW,&newtio);
00092 if (result == -1) {
00093 perror("GPS::GPS : tcsetattr failed");
00094 exit(EXIT_FAILURE);
00095 }
00096 }
00097
00108 int
00109 GPS::init(float period, int dynamicMode) {
00110
00111
00112 int flags;
00113 int result = fcntl(gps_fd, F_GETFL, &flags);
00114 if (result == -1) {
00115 perror("GPS::init() error with fcntl F_GETFL");
00116 return -1;
00117 }
00118 result = fcntl(gps_fd, F_SETFL, flags | O_NONBLOCK);
00119 if (result == -1) {
00120 perror("GPS::init() error with fcntl F_SETFL");
00121 return -1;
00122 }
00123
00124
00125 do {
00126 result = read(gps_fd, msgbuf, sizeof(msgbuf)-1);
00127 if (result == 0) {
00128 if (errno == EAGAIN) {
00129 break;
00130 } else {
00131 perror ("GPS::init() error with read");
00132 return -1;
00133 }
00134 }
00135 } while (result > 0);
00136
00137
00138 writeLine("$PASHS,RST\r\n");
00139 if (checkAck()) {
00140 cerr << "GPS::init() error - could not reset GPS - trying once more" << endl;
00141 sleep(3);
00142 writeLine("$PASHS,RST\r\n");
00143 if (checkAck()) {
00144 cerr << "GPS::init() error - could not reset GPS failing" << endl;
00145 return -1;
00146 }
00147 }
00148
00149
00150 writeLine("$PASHS,ALT,219.60\r\n");
00151 if (checkAck()) {
00152 cerr << "GPS::init() error - could not run set initial altitude on GPS" << endl;
00153 return -1;
00154 }
00155
00156 char msgtmp[40];
00157
00158
00159 snprintf(msgtmp, sizeof(msgtmp),"$PASHS,DYN,%d\r\n",dynamicMode);
00160 writeLine(msgtmp);
00161 if (checkAck()) {
00162 cerr << "GPS::init() error - could set dynamic mode on GPS" << endl;
00163 cerr << "GPS::init() - with command : " << msgtmp;
00164 return -1;
00165 }
00166
00167
00168 snprintf(msgtmp, sizeof(msgtmp),"$PASHS,NME,POS,A,ON,%f\r\n",period);
00169 writeLine(msgtmp);
00170 if (checkAck()) {
00171 cerr << "GPS::init() error - could not run NME,POS on GPS" << endl;
00172 cerr << "GPS::init() - with command : " << msgtmp;
00173 return -1;
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 result = fcntl(gps_fd, F_SETFL, flags);
00186 if (result == -1) {
00187 perror("GPS::init() error with fcntl F_SETFL (2)");
00188 return -1;
00189 }
00190
00191
00192 return 0;
00193 }
00194
00205 void
00206 GPS::initVars(void)
00207 {
00208
00209 invalid = nan("");
00210 msgbuf[0] = '\0';
00211
00212 using_file = 0;
00213 gps_fd = -1;
00214 msglen = 0;
00215 has_positions = has_velocities = 0;
00216 latitude = longitude = altitude = invalid;
00217 x = y = z = invalid;
00218 xvel = yvel = zvel = invalid;
00219 hVelocity = vVelocity = direction = invalid;
00220 pdop = hdop = vdop = tdop = invalid;
00221 }
00222
00223
00234 GPS::~GPS(void)
00235 {
00236 if (gps_fd != -1)
00237 close(gps_fd);
00238 }
00239
00240
00241
00243
00244
00245
00247
00257 int
00258 GPS::readLine(void)
00259 {
00260 int result;
00261
00262 for(int i=1; i<10; ++i) {
00263
00264 result = read(gps_fd, msgbuf, sizeof(msgbuf)-1);
00265 if (result == 0) {
00266 std::cerr << "GPS::readLine : serial port closed?" << std::endl;
00267
00268 return -1;
00269 }
00270 else if ((result == -1) && (errno != EAGAIN)) {
00271 std::cerr << "GPS::readLine error - " << strerror(errno) << std::endl;
00272
00273 return -1;
00274 }
00275 else if (result > 0) {
00276 msglen = result;
00277 std::cout << "GPS responded in " << i << " seconds\n";
00278 if (msgbuf[msglen-1] != '\n') {
00279 std::cerr << "GPS::Readline read didn't return a complete line" << std::endl;
00280
00281 return -1;
00282 }
00283 msgbuf[msglen] = '\0';
00284 return 0;
00285 }
00286
00287
00288 sleep(1);
00289
00290 }
00291
00292 return -1;
00293 }
00294
00295
00296
00298
00299
00301
00311 int
00312 GPS::writeLine(const char* msg)
00313 {
00314 int len = strlen(msg);
00315
00316
00317
00318
00319 int result = write(gps_fd,msg,len);
00320 if (result == -1) {
00321 std::cerr << "GPS::writeLine error writing to gps serial port : " << strerror(errno) << std::endl;
00322 return -1;
00323
00324 }
00325 else if (result != len) {
00326 std::cerr << "GPS::writeLine error, only wrote " << result << " bytes of " << len << std::endl;
00327 return -1;
00328
00329 }
00330
00331 return 0;
00332 }
00333
00334
00335
00336
00338
00339
00341
00351 int
00352 GPS::checkAck(void) {
00353 if ( readLine() ) {
00354 std::cerr << "GPS::checkAck : No repsonse from GPS unit" << std::endl;
00355 return -1;
00356 }
00357
00358 if (strcmp(msgbuf, "$PASHR,ACK*3D\r\n") == 0) {
00359 return 0;
00360 }
00361 else if (strcmp(msgbuf, "$PASHR,NAK*30\r\n") == 0) {
00362 std::cerr << "GPS::checkAck : recieved NAK message '" << msgbuf << ",\n";
00363 return -1;
00364
00365 }
00366 else {
00367 std::cerr << "GPS::checkAck : recieved unknown message '" << msgbuf << ",\n";
00368 return -1;
00369
00370 }
00371
00372 return -1;
00373 }
00374
00375
00377
00378
00379
00380
00382
00392 int
00393 GPS::Read(void) {
00394 int result;
00395
00396
00397 result = read(gps_fd, msgbuf, sizeof(msgbuf));
00398 if (result == 0) {
00399 std::cerr << "GPS::Read : serial port closed?" << std::endl;
00400
00401 return -1;
00402 }
00403 else if (result == -1) {
00404 if (errno == EAGAIN) {
00405 return 0;
00406 }
00407 else {
00408 std::cerr << "GPS::Read error - " << strerror(errno) << std::endl;
00409 return -1;
00410
00411 }
00412 }
00413
00414 if (result >= (int) sizeof(msgbuf)) {
00415 std::cerr << "GPS::ReadNoWait : message is longer than buffer" << std::endl;
00416 exit(EXIT_FAILURE);
00417 }
00418
00419 msglen = result;
00420 msgbuf[msglen] = '\0';
00421
00422
00423
00424 if ( (msgbuf[msglen-2] != '\r') ||
00425 (msgbuf[msglen-1] != '\n') ) {
00426 std::cerr << "GPS::ReadNoWait : missing EOL chars in '" << msgbuf << "'\n";
00427
00428 return -1;
00429 }
00430
00431 if (dispatchMsg(msgbuf) < 0) {
00432 cerr << "GPS::Read error parsing message '" << msgbuf << "'\n";
00433 return -1;
00434 }
00435 else
00436 return 1;
00437 }
00438
00439
00441
00442
00443
00445
00455 int
00456 GPS::dispatchMsg(const char* msg) {
00457 if (memcmp(msg,"$PASHR,POS",10) == 0) {
00458 return parsePOS(msg);
00459 }
00460 else if (memcmp(msgbuf,"$PASHR,UTM",10) == 0) {
00461 return parseUTM(msg);
00462 }
00463 else {
00464 cerr << "GPS::dispatchMsg - Unknown message '" << msg << '\'' << endl;
00465 return -1;
00466 }
00467 }
00468
00469
00470
00472
00473
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00496
00506 int
00507 GPS::parsePOS(const char* msg)
00508 {
00509
00510 enum {pashr=0, pos, d1, d2, m1, m2, c1, m3, c2, f1, f2, f3, f4, f5, f6, f7, f8, f9, s1, hh};
00511
00512
00513 const char *fieldarr[20], *field=msg, *lastfield=msg;
00514 fieldarr[0] = msg;
00515 for(int i=1; i<=18; ++i) {
00516 field = strchr(field, ',');
00517 if (field == NULL) {
00518 std::cerr << "GPS::read missing field from '" << lastfield << " iter=" << i << std::endl
00519 << " in '" << msg << "'\n";
00520 return -1;
00521 }
00522 ++field;
00523 fieldarr[i] = field;
00524 lastfield = field;
00525 }
00526
00527 field = strchr(field, '*');
00528 if (*field != '*') {
00529 std::cerr << "GPS::parsePOS missing checksum in '" << field << "'\n"
00530 << " in '" << msg << ",\n";
00531 return -1;
00532 }
00533 fieldarr[19] = field+1;
00534
00535
00536
00537
00538 if ( memcmp(fieldarr[pashr], "$PASHR,POS", 10) != 0 ) {
00539
00540
00541 std::cerr << "GPS::parsePOS incorrect message header '" << fieldarr[pashr] << ',' << fieldarr[pos] << "'\n";
00542 return -1;
00543 }
00544
00545
00546 if ( memcmp(fieldarr[s1],"DC00",4) != 0 ) {
00547 std::cerr << "GPS::parsePOS incorrect firmware version '" << fieldarr[s1] << "'\n";
00548 return -1;
00549 }
00550
00551 errno = 0;
00552 is_corrected = strtol(fieldarr[d1],NULL,10);
00553 numsat = strtol(fieldarr[d2],NULL,10);
00554 if (errno != 0) {
00555 std::cerr << "GPS::parsePOS - error converting decimal values : " << strerror(errno) << std::endl;
00556 return -1;
00557 }
00558
00559
00560 if ( (*fieldarr[m2] != ',') &&
00561 (*fieldarr[m3] != ',') &&
00562 (*fieldarr[c1] != ',') &&
00563 (*fieldarr[c2] != ',') &&
00564 (*fieldarr[f1] != ',') ) {
00565 has_positions = 1;
00566
00567 NorS = *fieldarr[c1];
00568 EorW = *fieldarr[c2];
00569
00570 if ( ((NorS != 'N') && (NorS != 'S')) ||
00571 ((EorW != 'E') && (EorW != 'W')) ) {
00572 std::cerr << "GPS::parsePOS - bad GPS region (N S E W) : in "
00573 << *fieldarr[c1] << *fieldarr[c2] << std::endl;
00574 return -1;
00575 }
00576
00577
00578 errno=0;
00579
00580 {
00581 char numbuf[3] = {*fieldarr[m2], *(fieldarr[m2]+1), '\0'};
00582 latitude = minutes2radians * strtod(fieldarr[m2]+2,NULL);
00583 latitude += degrees2radians * strtod(numbuf,NULL);
00584 }
00585
00586 {
00587 char numbuf[4] = {*fieldarr[m3], *(fieldarr[m3]+1), *(fieldarr[m3]+2), '\0'};
00588 longitude = minutes2radians * strtod(fieldarr[m3]+3,NULL);
00589 longitude += degrees2radians * strtod(numbuf,NULL);
00590 }
00591
00592 z = altitude = strtod(fieldarr[m1],NULL);
00593
00594 if (errno != 0) {
00595 std::cerr << "GPS::parsePOS - error converting longitude/latitude values : " << strerror(errno) << std::endl;
00596 return -1;
00597 }
00598
00599
00600 x = (latitude-zeroLatitude) * earthRadius;
00601 y = (longitude-zeroLongitude) * cos(latitude) * earthRadius;
00602
00603 }
00604 else {
00605
00606 has_positions = 0;
00607 latitude=longitude=invalid;
00608 x=y=z=invalid;
00609 }
00610
00611
00612 if ( (*fieldarr[f3] != ',') &&
00613 (*fieldarr[f4] != ',') &&
00614 (*fieldarr[f5] != ',') ) {
00615 has_velocities = 1;
00616 errno = 0;
00617
00618 direction = degrees2radians * strtod(fieldarr[f3],NULL);
00619 hVelocity = knots2mps * strtod(fieldarr[f4],NULL);
00620 vVelocity = strtod(fieldarr[f5],NULL);
00621 if (errno != 0) {
00622 std::cerr << "GPS::parsePOS - error converting velocity values to floats : " << strerror(errno) << std::endl;
00623 return -1;
00624 }
00625 xvel = cos(direction) * hVelocity;
00626 yvel = sin(direction) * hVelocity;
00627 } else {
00628 has_velocities = 0;
00629 direction = invalid;
00630 hVelocity = invalid;
00631 vVelocity = invalid;
00632 xvel = invalid;
00633 yvel = invalid;
00634 }
00635
00636
00637
00638 errno = 0;
00639 pdop = strtod(fieldarr[f6],NULL);
00640 hdop = strtod(fieldarr[f7],NULL);
00641 vdop = strtod(fieldarr[f8],NULL);
00642 tdop = strtod(fieldarr[f9],NULL);
00643 if (errno != 0) {
00644 std::cerr << "GPS::parsePOS - error converting *dop values to floats : " << strerror(errno) << std::endl;
00645 return -1;
00646 }
00647
00648 return 0;
00649 }
00650
00651
00652
00654
00655
00657
00658
00660
00670 int
00671 GPS::parseUTM(const char* msg)
00672 {
00673
00674 enum {pashr=0, pos, d1, d2, m1, m2, c1, m3, c2, f1, f2, f3, f4, f5, f6, f7, f8, f9, s1, hh};
00675
00676
00677 const char *fieldarr[20], *field=msg, *lastfield=msg;
00678 fieldarr[0] = msg;
00679 for(int i=1; i<=18; ++i) {
00680 field = strchr(field, ',');
00681 if (field == NULL) {
00682 std::cerr << "GPS::read missing field from '" << lastfield << " iter=" << i << std::endl
00683 << " in '" << msg << "'\n";
00684 return -1;
00685 }
00686 ++field;
00687 fieldarr[i] = field;
00688 lastfield = field;
00689 }
00690
00691 field = strchr(field, '*');
00692 if (*field != '*') {
00693 std::cerr << "GPS::parsePOS missing checksum in '" << field << "'\n"
00694 << " in '" << msg << ",\n";
00695 return -1;
00696 }
00697 fieldarr[19] = field+1;
00698
00699
00700
00701
00702 if ( memcmp(fieldarr[pashr], "$PASHR,POS", 10) != 0 ) {
00703
00704
00705 std::cerr << "GPS::parsePOS incorrect message header '" << fieldarr[pashr] << ',' << fieldarr[pos] << "'\n";
00706 return -1;
00707 }
00708
00709
00710 if ( memcmp(fieldarr[s1],"DC00",4) != 0 ) {
00711 std::cerr << "GPS::parsePOS incorrect firmware version '" << fieldarr[s1] << "'\n";
00712 return -1;
00713 }
00714
00715 errno = 0;
00716 is_corrected = strtol(fieldarr[d1],NULL,10);
00717 numsat = strtol(fieldarr[d2],NULL,10);
00718 if (errno != 0) {
00719 std::cerr << "GPS::parsePOS - error converting decimal values : " << strerror(errno) << std::endl;
00720 return -1;
00721 }
00722
00723
00724 if ( (*fieldarr[m2] != ',') &&
00725 (*fieldarr[m3] != ',') &&
00726 (*fieldarr[c1] != ',') &&
00727 (*fieldarr[c2] != ',') &&
00728 (*fieldarr[f1] != ',') ) {
00729 has_positions = 1;
00730
00731 NorS = *fieldarr[c1];
00732 EorW = *fieldarr[c2];
00733
00734 if ( ((NorS != 'N') && (NorS != 'S')) ||
00735 ((EorW != 'E') && (EorW != 'W')) ) {
00736 std::cerr << "GPS::parsePOS - bad GPS region (N S E W) : in "
00737 << *fieldarr[c1] << *fieldarr[c2] << std::endl;
00738 return -1;
00739 }
00740
00741
00742 errno=0;
00743
00744 {
00745 char numbuf[3] = {*fieldarr[m2], *(fieldarr[m2]+1), '\0'};
00746 latitude = minutes2radians * strtod(fieldarr[m2]+2,NULL);
00747 latitude += degrees2radians * strtod(numbuf,NULL);
00748 }
00749
00750 {
00751 char numbuf[4] = {*fieldarr[m3], *(fieldarr[m3]+1), *(fieldarr[m3]+2), '\0'};
00752 longitude = minutes2radians * strtod(fieldarr[m3]+3,NULL);
00753 longitude += degrees2radians * strtod(numbuf,NULL);
00754 }
00755
00756 z = altitude = strtod(fieldarr[m1],NULL);
00757
00758 if (errno != 0) {
00759 std::cerr << "GPS::parsePOS - error converting longitude/latitude values : " << strerror(errno) << std::endl;
00760 return -1;
00761 }
00762
00763
00764 x = (latitude-zeroLatitude) * earthRadius;
00765 y = (longitude-zeroLongitude) * cos(latitude) * earthRadius;
00766
00767 }
00768 else {
00769
00770 has_positions = 0;
00771 latitude=longitude=invalid;
00772 x=y=z=invalid;
00773 }
00774
00775
00776 if ( (*fieldarr[f3] != ',') &&
00777 (*fieldarr[f4] != ',') &&
00778 (*fieldarr[f5] != ',') ) {
00779 has_velocities = 1;
00780 errno = 0;
00781
00782 direction = degrees2radians * strtod(fieldarr[f3],NULL);
00783 hVelocity = knots2mps * strtod(fieldarr[f4],NULL);
00784 vVelocity = strtod(fieldarr[f5],NULL);
00785 if (errno != 0) {
00786 std::cerr << "GPS::parsePOS - error converting velocity values to floats : " << strerror(errno) << std::endl;
00787 return -1;
00788 }
00789 } else {
00790 has_velocities = 0;
00791 direction = invalid;
00792 hVelocity = invalid;
00793 vVelocity = invalid;
00794 }
00795
00796
00797
00798 errno = 0;
00799 pdop = strtod(fieldarr[f6],NULL);
00800 hdop = strtod(fieldarr[f7],NULL);
00801 vdop = strtod(fieldarr[f8],NULL);
00802 tdop = strtod(fieldarr[f9],NULL);
00803 if (errno != 0) {
00804 std::cerr << "GPS::parsePOS - error converting *dop values to floats : " << strerror(errno) << std::endl;
00805 return -1;
00806 }
00807
00808 return 0;
00809 }
00810
00811
00812
00814
00816
00826 void
00827 GPS::printData(void) {
00828 std::cout
00829 << numsat << " Satellites, " << std::endl;
00830
00831 if (has_positions)
00832 std::cout
00833 << "lat = " << latitude << " rads, long = " << longitude << " rads, " << NorS << EorW << std::endl
00834 << " [x,y,z] pos = [" << x << ',' << y << ',' << z << ']' << std::endl;
00835
00836 if (has_velocities)
00837 std::cout
00838 << "dir = " << direction << ", hVel = " << hVelocity << ", vVel = " << vVelocity << std::endl
00839 << " [x,y,z] vel = [" << xvel << ',' << yvel << ',' << zvel << ']' << std::endl;
00840
00841 std::cout << "DOP : P=" << pdop << " H=" << hdop << " V=" << vdop << " T=" << tdop << std::endl;
00842
00843 }