00001
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <errno.h>
00005 #include <stdarg.h>
00006 #include <unistd.h>
00007 #include <ctype.h>
00008 #include <fcntl.h>
00009 #include <math.h>
00010 #include <poll.h>
00011 #include <limits.h>
00012 #define FILE_LOGGING 0
00013 #include "ocean.h"
00014 #include "ros/time.h"
00015
00016 using namespace willowgarage::ocean;
00017
00018
00019 const int ocean::NMEA_MAX;
00020 const int ocean::MAXTAGLEN;
00021 const int ocean::MAXCHANNELS;
00022
00023 const int ocean::INPUT_BUF_SIZE;
00024 const int ocean::OUTPUT_BUF_SIZE;
00025 const unsigned int ocean::MAX_PACKET_LENGTH;
00026 const int ocean::BAD_PACKET;
00027 const int ocean::NO_PACKET;
00028 const int ocean::NMEA_PACKET;
00029
00030
00031
00032
00033 const struct ocean::regPair ocean::regList[] = {
00034 {"Manufacturer Access" ,"" , 0x00},
00035 {"Remaining Capacity Alarm" ,"" , 0x01},
00036 {"Remaining Time Alarm" ,"min" , 0x02},
00037 {"Battery Mode" ,"" , 0x03},
00038 {"At Rate" ,"mA" , 0x04},
00039 {"At Rate Time To Full" ,"min" , 0x05},
00040 {"At Rate Time To Empty" ,"min" , 0x06},
00041 {"At Rate OK" ,"bool" , 0x07},
00042 {"Temperature" ,"0.1 K" , 0x08},
00043 {"Voltage" ,"mV" , 0x09},
00044 {"Current" ,"mA" , 0x0a},
00045 {"Average Current" ,"mA" , 0x0b},
00046 {"Max Error" ,"%" , 0x0c},
00047 {"Relative State Of Charge" ,"%" , 0x0d},
00048 {"Absolute State Of Charge" ,"%" , 0x0e},
00049 {"Remaining Capacity" ,"mAh" , 0x0f},
00050 {"Full Charge Capacity" ,"mAh" , 0x10},
00051 {"Run Time To Empty" ,"min" , 0x11},
00052 {"Average Time To Empty" ,"min" , 0x12},
00053 {"Average Time To Full" ,"min" , 0x13},
00054 {"Battery Status" ,"" , 0x16},
00055 {"Cycle Count" ,"cycle" , 0x17},
00056 {"Design Capacity" ,"mAh" , 0x18},
00057 {"Design Voltage" ,"mV" , 0x19},
00058 {"Specification Info" ,"" , 0x1a},
00059 {"Manufacture Date" ,"DMY" , 0x1b},
00060 {"Serial Number" ,"uint" , 0x1c},
00061 {"Manufacture Name" ,"string", 0x20},
00062 {"Device Name" ,"string", 0x21},
00063 {"Device Chemistry" ,"string", 0x22},
00064 {"Manufacture Data" ,"" , 0x23}
00065 };
00066 const unsigned ocean::regListLength(sizeof(regList)/ sizeof(struct regPair));
00072 ocean::ocean ( int id, int debug)
00073 {
00074 debuglevel = debug;
00075 server.id = id;
00076 server.battery.resize(4);
00077
00078
00079 for (uint i = 0; i < server.battery.size(); ++i)
00080 server.battery[i].last_battery_update = ros::Time(-1);
00081 }
00082
00083 ocean::~ocean ()
00084 {
00085 if (close (inputDevice) != 0)
00086 {
00087 fprintf (stderr, "failed closing serial device: %s\n", strerror (errno));
00088 }
00089 }
00090
00091 void
00092 ocean::setDebugLevel (int level)
00093 {
00094 debuglevel = level;
00095 }
00096
00097 void
00098 ocean::initialize (const std::string &input_dev)
00099 {
00100 inputDevice = open (input_dev.c_str(), O_RDWR | O_NOCTTY);
00101
00102 if (inputDevice < 0)
00103 {
00104 fprintf (stderr, "failed to open tty device [%s]: %s\n", input_dev.c_str(), strerror (errno));
00105 }
00106 if (isatty (inputDevice) != 1)
00107 {
00108 fprintf (stderr, "Device [%s] not a tty device.\n", input_dev.c_str());
00109 }
00110 report (2, "Device opened dev=%d\n", inputDevice);
00111
00112 tcgetattr (inputDevice, &ttyset);
00113
00114 ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS);
00115 ttyset.c_cflag |= CREAD | CLOCAL;
00116 ttyset.c_iflag = ttyset.c_oflag = ttyset.c_lflag = (tcflag_t) 0;
00117
00118 set_speed (19200);
00119
00120 #if (FILE_LOGGING > 0)
00121 char logname[128];
00122 sprintf ( logname, "/tmp/oceanServer%c.log", input_dev[input_dev.length()-1]);
00123 report (2, "Logging to file: %s\n", logname);
00124
00125 outputFile = open( logname, (O_WRONLY | O_APPEND ) );
00126
00127 if(outputFile < 0)
00128 {
00129 if(errno == ENOENT )
00130 {
00131 outputFile = open( logname, (O_WRONLY | O_CREAT), (S_IRWXU | S_IRWXG) );
00132 }
00133
00134 if((outputFile < 0))
00135 {
00136 report (2, "Failed to open log file: %d\n", errno);
00137 close(inputDevice);
00138 exit(outputFile);
00139 }
00140 }
00141 #endif
00142
00143 if(commTest())
00144 resetOcean();
00145
00146 }
00147
00148 long int ocean::convertStringBase16( const char* input )
00149 {
00150 char *endptr;
00151 errno = 0;
00152
00153 if( input == NULL )
00154 {
00155 report (1, "convertStringBase16 input NULL\n");
00156 return 0;
00157 }
00158
00159 long int result = strtol( input, &endptr, 16 );
00160 if( ((errno == ERANGE) && (( result == LONG_MIN ) || ( result == LONG_MAX ))) || ((errno != 0) && (result == 0)))
00161 {
00162 report (0, "strtol failure\n");
00163 return 0;
00164 }
00165
00166 if( endptr == input )
00167 {
00168 report (0, "strtol No digits found\n");
00169 return 0;
00170 }
00171
00172 if( *endptr != '\0' )
00173 report( 1, "strtol characters left after conversion: %s\n", endptr);
00174
00175 return result;
00176 }
00177
00178 void
00179 ocean::read_file (const std::string &input)
00180 {
00181 inputDevice = open (input.c_str(), O_RDONLY);
00182 if (inputDevice < 0)
00183 {
00184 fprintf (stderr, "failed to open tty file [%s]: %s\n", input.c_str(), strerror (errno));
00185 }
00186
00187 packet_reset();
00188 }
00189
00190 int ocean::commTest()
00191 {
00192 int maxTries = 10;
00193 fd_set rfds;
00194 struct timeval tv;
00195 int retval;
00196
00197 packet_reset();
00198
00199 int listenCount = 50;
00200 do
00201 {
00202 maxTries = 10;
00203
00204 while((packetType != NMEA_PACKET) && (maxTries--))
00205 {
00206 report(5,"commTest: call packet_get\n");
00207 int result = NO_PACKET;
00208
00209 FD_ZERO(&rfds);
00210 FD_SET(inputDevice, &rfds);
00211 tv.tv_sec = 2;
00212 tv.tv_usec = 0;
00213
00214 retval = select( inputDevice + 1, &rfds, NULL, NULL, &tv);
00215 if(retval < 0)
00216 report(0, "select error\n");
00217 else if(retval > 0)
00218 {
00219 {
00220 report(5, "calling packet_get\n");
00221 result = packet_get();
00222 }
00223 }
00224 else
00225 {
00226 report(2, "select timeout\n");
00227 listenCount -= 10;
00228 maxTries = 0;
00229 }
00230 usleep(1000);
00231 }
00232
00233 if(packetType == NMEA_PACKET)
00234 {
00235 report(5,"NMEA packet\n");
00236 if(nmea_parse() > 0)
00237 {
00238 return(0);
00239 }
00240 } else
00241 report(5,"non NMEA packet\n");
00242
00243 report(6, "listenCount=%d\n", listenCount);
00244 } while( listenCount-- > 0);
00245
00246 return(-1);
00247 }
00248
00249 void
00250 ocean::resetOcean()
00251 {
00252 report(5, "Sending ocean reset string\n");
00253 string_send(" ");
00254 usleep(1000);
00255 string_send("x");
00256 usleep(1000);
00257 }
00258
00259 int
00260 ocean::run (void)
00261 {
00262 int status (0);
00263
00264 packet_get ();
00265 if (packetType == NMEA_PACKET)
00266 {
00267 status = nmea_parse ();
00268 }
00269 return status;
00270 }
00271
00275 void
00276 ocean::flush (void)
00277 {
00278 tcflush (inputDevice, TCIOFLUSH);
00279 }
00280
00281
00282 int
00283 ocean::get_speed (void)
00284 {
00285 speed_t code = cfgetospeed (&ttyset);
00286 switch (code)
00287 {
00288 case B0:
00289 return (0);
00290 case B300:
00291 return (300);
00292 case B1200:
00293 return (1200);
00294 case B2400:
00295 return (2400);
00296 case B4800:
00297 return (4800);
00298 case B9600:
00299 return (9600);
00300 case B19200:
00301 return (19200);
00302 case B38400:
00303 return (38400);
00304 case B57600:
00305 return (57600);
00306 default:
00307 return (115200);
00308 }
00309 }
00310
00311 void
00312 ocean::set_speed (int newspeed)
00313 {
00314 unsigned int rate;
00315 if (newspeed < 300)
00316 rate = B0;
00317 else if (newspeed < 1200)
00318 rate = B300;
00319 else if (newspeed < 2400)
00320 rate = B1200;
00321 else if (newspeed < 4800)
00322 rate = B2400;
00323 else if (newspeed < 9600)
00324 rate = B4800;
00325 else if (newspeed < 19200)
00326 rate = B9600;
00327 else if (newspeed < 38400)
00328 rate = B19200;
00329 else if (newspeed < 57600)
00330 rate = B38400;
00331 else if (newspeed < 115200)
00332 rate = B57600;
00333 else
00334 rate = B115200;
00335
00336 if (cfsetispeed (&ttyset, B0) != 0)
00337 report (0, "Failed setting input speed\n");
00338 if (cfsetospeed (&ttyset, rate) != 0)
00339 report (0, "Failed setting output speed\n");
00340
00341 ttyset.c_iflag &= ~(PARMRK | INPCK);
00342 ttyset.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
00343
00344 ttyset.c_cflag |= CS8;
00345
00346 if (tcsetattr (inputDevice, TCSANOW, &ttyset) != 0)
00347 report (0, "Failed to configure serial device\n");
00348
00349 flush ();
00350 report (1, "set_speed speed=%d rate=%x\n", newspeed, rate);
00351
00352 currentBaudRate = (unsigned int) newspeed;
00353 packet_reset ();
00354 }
00355
00356 void
00357 ocean::report (int errlevel, const char *fmt, ...)
00358 {
00359 if (errlevel <= debuglevel)
00360 {
00361 char buf[BUFSIZ], buf2[BUFSIZ], *sp;
00362 va_list ap;
00363
00364 (void) strcpy (buf, "ocean: ");
00365 va_start (ap, fmt);
00366 (void) vsnprintf (buf + strlen (buf), sizeof (buf) - strlen (buf), fmt,
00367 ap);
00368 va_end (ap);
00369
00370 buf2[0] = '\0';
00371 for (sp = buf; *sp != '\0'; sp++)
00372 if (isprint (*sp)
00373 || (isspace (*sp) && (sp[1] == '\0' || sp[2] == '\0')))
00374 (void) snprintf (buf2 + strlen (buf2), 2, "%c", *sp);
00375 else
00376 (void) snprintf (buf2 + strlen (buf2), 6, "\\x%02x", (unsigned) *sp);
00377
00378 (void) fputs (buf2, stderr);
00379 }
00380 }
00381
00382
00383 enum
00384 {
00385 GROUND_STATE,
00386 NMEA_DOLLAR,
00387 NMEA_PUB_LEAD,
00388 NMEA_LEADER_END,
00389 NMEA_CR,
00390 NMEA_RECOGNIZED
00391 };
00392
00393 char *
00394 ocean::gpsd_hexdump (void *binbuf, size_t binbuflen)
00395 {
00396 static char hexbuf[MAX_PACKET_LENGTH * 2 + 1];
00397 size_t i;
00398 size_t len =
00399 (size_t) ((binbuflen >
00400 MAX_PACKET_LENGTH) ? MAX_PACKET_LENGTH : binbuflen);
00401 char *ibuf = (char *) binbuf;
00402 memset (hexbuf, 0, sizeof (hexbuf));
00403
00404 for (i = 0; i < len; i++)
00405 {
00406 (void) snprintf (hexbuf + (2 * i), 3, "%02x",
00407 (unsigned int) (ibuf[i] & 0xff));
00408 }
00409 return hexbuf;
00410 }
00411
00417 void
00418 ocean::nextstate (unsigned char c)
00419 {
00420 switch (packetState)
00421 {
00422 case GROUND_STATE:
00423 if (c == '$')
00424 {
00425 packetState = NMEA_DOLLAR;
00426 }
00427 break;
00428
00429 case NMEA_DOLLAR:
00430 if (c == 'S')
00431 packetState = NMEA_LEADER_END;
00432 else if (c == 'C')
00433 packetState = NMEA_LEADER_END;
00434 else if (c == 'B')
00435
00436 packetState = NMEA_LEADER_END;
00437 else
00438 packetState = GROUND_STATE;
00439 break;
00440
00441
00442
00443
00444
00445
00446
00447
00448 case NMEA_LEADER_END:
00449 if (c == '\r')
00450 packetState = NMEA_CR;
00451 else if (c == '\n')
00452
00453 packetState = NMEA_RECOGNIZED;
00454 else if (c == '$')
00455
00456 packetState = NMEA_DOLLAR;
00457 else if (!isprint (c))
00458 packetState = GROUND_STATE;
00459 break;
00460
00461 case NMEA_CR:
00462 if (c == '\n')
00463 packetState = NMEA_RECOGNIZED;
00464 else
00465 packetState = GROUND_STATE;
00466 break;
00467 case NMEA_RECOGNIZED:
00468 if (c == '$')
00469 packetState = NMEA_DOLLAR;
00470 else
00471 packetState = GROUND_STATE;
00472 break;
00473
00474 }
00475 }
00476
00477 #define STATE_DEBUG
00478
00479
00480 void
00481 ocean::packet_accept (int packet_type)
00482 {
00483 size_t packetlen = inbufptr - inbuffer;
00484 if (packetlen < sizeof (outbuffer))
00485 {
00486 memcpy ((void *) outbuffer, (void *) inbuffer, packetlen);
00487 outbuflen = packetlen;
00488 outbuffer[packetlen] = '\0';
00489 packetType = packet_type;
00490 #ifdef STATE_DEBUG
00491 report (6, "Packet type %d accepted %d = %s\n",
00492 packet_type, packetlen, gpsd_hexdump (outbuffer, outbuflen));
00493 #endif
00494 }
00495 else
00496 {
00497 report (1, "Rejected too long packet type %d len %d\n",
00498 packet_type, packetlen);
00499 }
00500 }
00501
00502
00503 void
00504 ocean::packet_discard ()
00505 {
00506 size_t discard = inbufptr - inbuffer;
00507 size_t remaining = inbuflen - discard;
00508 inbufptr = (unsigned char *) memmove (inbuffer, inbufptr, remaining);
00509 inbuflen = remaining;
00510 #ifdef STATE_DEBUG
00511 report (6, "Packet discard of %d, chars remaining is %d = %s\n",
00512 discard, remaining, gpsd_hexdump (inbuffer, inbuflen));
00513 #endif
00514 }
00515
00516
00517 void
00518 ocean::character_discard ()
00519 {
00520 memmove (inbuffer, inbuffer + 1, (size_t)-- inbuflen);
00521 inbufptr = inbuffer;
00522 #ifdef STATE_DEBUG
00523 report (6, "Character discarded, buffer %d chars = %s\n",
00524 inbuflen, gpsd_hexdump (inbuffer, inbuflen));
00525 #endif
00526 }
00527
00528
00529
00530
00531
00532 #define getword(i) (short)(session->inbuffer[2*(i)] | (session->inbuffer[2*(i)+1] << 8))
00533
00534
00535
00536 ssize_t
00537 ocean::packet_parse (size_t newdata)
00538 {
00539 #ifdef STATE_DEBUG
00540 report (6, "Read %d chars to buffer offset %d (total %d): %s\n",
00541 newdata,
00542 inbuflen, inbuflen + newdata, gpsd_hexdump (inbufptr, newdata));
00543 #endif
00544
00545 outbuflen = 0;
00546 inbuflen += newdata;
00547 #if 0
00548 inbuffer[inbuflen] = '\0';
00549
00550 report (5, "Input buffer: %s\n", inbuffer);
00551 #endif
00552 while (inbufptr < (inbuffer + inbuflen))
00553 {
00554 unsigned char c = *inbufptr++;
00555 static const char *state_table[] = {
00556 "GROUND_STATE",
00557 "NMEA_DOLLAR",
00558 "NMEA_PUB_LEAD",
00559 "NMEA_LEADER_END",
00560 "NMEA_CR",
00561 "NMEA_RECOGNIZED"
00562 };
00563 nextstate (c);
00564 report (7, "%08ld: character '%c' [%02x], new state: %s\n",
00565 char_counter,
00566 (isprint (c) ? c : '.'), c, state_table[packetState]);
00567 char_counter++;
00568
00569 if (packetState == GROUND_STATE)
00570 {
00571 character_discard ();
00572 }
00573 else if (packetState == NMEA_RECOGNIZED)
00574 {
00575 bool checksum_ok = true;
00576 char csum[3];
00577 char *trailer = (char *) inbufptr - 5;
00578
00579 if (*trailer == '%')
00580 {
00581 unsigned int n, crc = 0;
00582 for (n = 1; (char *) inbuffer + n < trailer; n++)
00583 crc ^= inbuffer[n];
00584 (void) snprintf (csum, sizeof (csum), "%02X", crc);
00585 checksum_ok = (toupper (csum[0]) == toupper (trailer[1])
00586 && toupper (csum[1]) == toupper (trailer[2]));
00587
00588 }
00589 if (checksum_ok)
00590 packet_accept (NMEA_PACKET);
00591
00592 packetState = GROUND_STATE;
00593 packet_discard ();
00594 break;
00595 }
00596 }
00597
00598 return (ssize_t) newdata;
00599 }
00600
00601 #undef getword
00602
00603
00604 ssize_t
00605 ocean::packet_get ()
00606 {
00607 ssize_t newdata;
00608 newdata =
00609 read (inputDevice, inbuffer + inbuflen, sizeof (inbuffer) - (inbuflen));
00610 if ((newdata < 0) && (errno != EAGAIN))
00611 return BAD_PACKET;
00612 else if ((newdata == 0) || ((newdata < 0) && (errno == EAGAIN)))
00613 return NO_PACKET;
00614
00615 #if (FILE_LOGGING > 0)
00616 write( outputFile, inbuffer + inbuflen, newdata );
00617 #endif
00618
00619 return packet_parse ((size_t) newdata);
00620 }
00621
00622
00623 void
00624 ocean::packet_reset ()
00625 {
00626 packetState = GROUND_STATE;
00627 inbuflen = 0;
00628 inbufptr = inbuffer;
00629 packetType = NO_PACKET;
00630 }
00631
00636
00637
00638
00639
00640
00641 unsigned int ocean::processSystem (int count, char *field[])
00642 {
00643 report (2, "processSystem message\n");
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 server.last_system_update = ros::Time::now();
00655
00656 for( int index = 1; index < count; )
00657 {
00658
00659 int tmp = atoi(field[index]);
00660 ++index;
00661 if( field[index] != NULL )
00662 {
00663 switch(tmp)
00664 {
00665 case 1:
00666 server.time_left.fromSec((double)convertStringBase16(field[index]) * 60);
00667 report (5, "timeLeft=%d\n", server.time_left.sec);
00668 break;
00669 case 3:
00670 server.message.assign(field[index]);
00671
00672 report (5, "processSystem message=%s\n", server.message.c_str());
00673 break;
00674 case 4:
00675 server.average_charge = (int32_t)convertStringBase16(field[index]);
00676 report (5, "averageCharge=%x\n", server.average_charge);
00677 break;
00678 default:
00679 ;
00680 }
00681 }
00682 ++index;
00683 }
00684
00685 return 0;
00686 }
00687
00688 unsigned int ocean::processController (int count, char *field[])
00689 {
00690 report (2, "processController message\n");
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710 server.last_controller_update = ros::Time::now();
00711
00712 for( int index = 1; index < count; )
00713 {
00714 int tmp = atoi (field[index]);
00715 ++index;
00716
00717 long int value = convertStringBase16(field[index]);
00718 report (5, "switch=%d value=0x%x\n", tmp, value);
00719
00720
00721
00722
00723
00724
00725
00726
00727 {
00728 switch(tmp)
00729 {
00730 case 1:
00731 {
00732 for(int xx = 0; xx < server.MAX_BAT_COUNT; ++xx)
00733 {
00734 server.battery[xx].present = value & 1;
00735 value = value >> 1;
00736 }
00737 }
00738 break;
00739 case 2:
00740 {
00741 for(int xx = 0; xx < server.MAX_BAT_COUNT; ++xx)
00742 {
00743 server.battery[xx].charging = value & 1;
00744 value = value >> 1;
00745 }
00746 }
00747 break;
00748 case 3:
00749 {
00750 for(int xx = 0; xx < server.MAX_BAT_COUNT; ++xx)
00751 {
00752 server.battery[xx].discharging = value & 1;
00753 value = value >> 1;
00754 }
00755 }
00756 break;
00757 case 4:
00758 #if 0 //we don't care about reserved. --Curt
00759 {
00760 for(int xx = 0; xx < server.MAX_BAT_COUNT; ++xx)
00761 {
00762 server.battery[xx].reserved = value & 1;
00763 value = value >> 1;
00764 }
00765 }
00766 #endif
00767 break;
00768 case 5:
00769 {
00770 for(int xx = 0; xx < server.MAX_BAT_COUNT; ++xx)
00771 {
00772 server.battery[xx].power_present = value & 1;
00773 value = value >> 1;
00774 }
00775 }
00776 break;
00777 case 6:
00778 {
00779 for(int xx = 0; xx < server.MAX_BAT_COUNT; ++xx)
00780 {
00781 server.battery[xx].power_no_good = value & 1;
00782 value = value >> 1;
00783 }
00784 }
00785 break;
00786 case 7:
00787 {
00788 for(int xx = 0; xx < server.MAX_BAT_COUNT; ++xx)
00789 {
00790 server.battery[xx].inhibited = value & 1;
00791 value = value >> 1;
00792 }
00793 }
00794 break;
00795 }
00796 }
00797 ++index;
00798 }
00799
00800 return 0;
00801 }
00802
00803 unsigned int ocean::processBattery (int count, char *field[])
00804 {
00805
00806 report (2, "processBattery %s\n", field[0]);
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818 unsigned int battery = (unsigned int)(field[0][2] - '0');
00819 --battery;
00820 report (5, "processBattery count=%d \n", count);
00821 report (5, "currentBattery=%d \n", battery);
00822
00823 server.battery[battery].last_battery_update = ros::Time::now();
00824 --count;
00825
00826 #if 0
00827 if( (count & 1) == 1 )
00828 {
00829 report (0, "received odd count=%d \n", count);
00830 count = count & 0xFE;
00831 }
00832 #endif
00833
00834 int32_t regNumber;
00835 int16_t value;
00836 unsigned int xx = 1;
00837 while(count > 1)
00838 {
00839 regNumber = (unsigned int)convertStringBase16( field[xx] );
00840 ++xx;
00841 value = (unsigned int)convertStringBase16( field[xx] );
00842 ++xx;
00843 report (5, "reg[%u]=%x \n", regNumber, value);
00844 if(regNumber >= server.MAX_BAT_REG)
00845 {
00846 report (2, "Register greater than expected: %x MAX_BAT_REG=%x\n", regNumber, server.MAX_BAT_REG);
00847 }
00848 else
00849 {
00850 server.battery[battery].battery_register[regNumber] = value;
00851 server.battery[battery].battery_update_flag[regNumber] = 1;
00852 server.battery[battery].battery_register_update[regNumber] = ros::Time::now();
00853 }
00854
00855 count -= 2;
00856 }
00857
00858 return 0;
00859 }
00860
00861
00862
00863
00864
00865
00866
00867
00868 unsigned int
00869 ocean::nmea_parse ()
00870 {
00871 static struct
00872 {
00873 const char *name;
00874 int funcNum;
00875 } nmea_phrase[] =
00876 {
00877 {
00878 "S", 1},
00879 {
00880 "C1", 2},
00881 {
00882 "B1", 3},
00883 };
00884 char buf[NMEA_MAX + 1];
00885 static char zeroStr[] = "0";
00886
00887 int count;
00888 unsigned int retval = 0;
00889 unsigned int i;
00890 char *p, *field[NMEA_MAX], *s;
00891
00892
00893 strncpy (buf, (const char *) outbuffer, NMEA_MAX);
00894
00895
00896 for (p = buf; (*p != '%') && (*p >= ' ');)
00897 ++p;
00898
00899 *p = '\0';
00900
00901
00902 for (count = 0, p = (char *) buf; (p != 0) && (*p != 0); p = strchr (p, ','))
00903 {
00904 *p = 0;
00905 ++p;
00906 if ((*p) != ',')
00907 {
00908 field[count] = p;
00909 }
00910 else
00911 field[count] = zeroStr;
00912
00913 ++count;
00914 }
00915
00916
00917 for (i = 0; i < (unsigned) (sizeof (nmea_phrase) / sizeof (nmea_phrase[0])); ++i)
00918 {
00919 s = field[0];
00920
00921
00922 if (strncmp (nmea_phrase[i].name, s, 2) == 0)
00923 {
00924 switch (nmea_phrase[i].funcNum)
00925 {
00926 case 1:
00927 processSystem (count, field);
00928 retval = 1;
00929 break;
00930 case 2:
00931 processController (count, field);
00932 retval = 2;
00933 break;
00934 case 3:
00935 processBattery (count, field);
00936 retval = 3;
00937 break;
00938 default:
00939 retval = 0;
00940 break;
00941 }
00942
00943 strncpy (tag, nmea_phrase[i].name, MAXTAGLEN);
00944 sentenceLength = strlen ((const char *) outbuffer);
00945 report (5, "Got Packet: type=%s\n", tag);
00946 break;
00947 }
00948 }
00949 packetType = NO_PACKET;
00950 return retval;
00951 }
00952
00953
00954 void
00955 ocean::nmea_add_checksum (char *sentence)
00956 {
00957 unsigned char sum = '\0';
00958 char c, *p = sentence;
00959
00960 if (*p == '$')
00961 {
00962 p++;
00963 }
00964 else
00965 {
00966 report (1, "Bad NMEA sentence: '%s'\n", sentence);
00967 }
00968 while (((c = *p) != '*') && (c != '\0'))
00969 {
00970 sum ^= c;
00971 p++;
00972 }
00973 *p++ = '*';
00974 (void) snprintf (p, 5, "%02X\r\n", (unsigned) sum);
00975 }
00976
00977
00978 int
00979 ocean::nmea_send (const char *fmt, ...)
00980 {
00981 int status;
00982 char buf[BUFSIZ];
00983 va_list ap;
00984
00985 va_start (ap, fmt);
00986 (void) vsnprintf (buf, sizeof (buf) - 5, fmt, ap);
00987 va_end (ap);
00988 if (fmt[0] == '$')
00989 {
00990 strcat (buf, "*");
00991 nmea_add_checksum (buf);
00992 }
00993 else
00994 strcat (buf, "\r\n");
00995 status = (int) write (inputDevice, buf, strlen (buf));
00996 if (status == (int) strlen (buf))
00997 {
00998 report (3, "=> OCEAN: %s\n", buf);
00999 return status;
01000 }
01001 else
01002 {
01003 report (3, "=> OCEAN: %s FAILED\n", buf);
01004 return -1;
01005 }
01006 }
01007
01008 int
01009 ocean::string_send (const char *fmt, ...)
01010 {
01011 int status;
01012 char buf[BUFSIZ];
01013 va_list ap;
01014
01015 va_start (ap, fmt);
01016 (void) vsnprintf (buf, sizeof (buf) - 5, fmt, ap);
01017 va_end (ap);
01018 status = (int) write (inputDevice, buf, strlen (buf));
01019 if (status == (int) strlen (buf))
01020 {
01021 report (3, "=> Ocean: %s\n", buf);
01022 return status;
01023 }
01024 else
01025 {
01026 report (3, "=> Ocean: %s FAILED\n", buf);
01027 return -1;
01028 }
01029 }
01030