Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages | Examples

ArSerialConnection_LIN.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "ArExport.h"
00027 #include "ariaOSDef.h"
00028 #include <sys/time.h>
00029 #include <termios.h>
00030 #include <unistd.h>
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <sys/ioctl.h>
00034 #include <fcntl.h>
00035 #include <errno.h>
00036 
00037 #include "ArSerialConnection.h"
00038 #include "ArLog.h"
00039 #include "ariaUtil.h"
00040 
00041 
00042 AREXPORT ArSerialConnection::ArSerialConnection()
00043 {
00044   myPort = -1;
00045   myPortName = "none";
00046   myBaudRate = 9600;
00047   myHardwareControl = false;
00048   myStatus = STATUS_NEVER_OPENED;
00049   myTakingTimeStamps = false;
00050   buildStrMap();
00051 }
00052 
00053 AREXPORT ArSerialConnection::~ArSerialConnection()
00054 {
00055   if (myPort != -1)
00056     close();
00057 }
00058 
00059 void ArSerialConnection::buildStrMap(void)
00060 {
00061   myStrMap[OPEN_COULD_NOT_OPEN_PORT] = "Could not open serial port.";
00062   myStrMap[OPEN_COULD_NOT_SET_UP_PORT] = "Could not set up serial port.";
00063   myStrMap[OPEN_INVALID_BAUD_RATE] = "Baud rate invalid, could not set baud on serial port.";
00064   myStrMap[OPEN_COULD_NOT_SET_BAUD] = "Could not set baud rate on serial port.";
00065   myStrMap[OPEN_ALREADY_OPEN] = "Serial port already open.";
00066 }
00067 
00068 AREXPORT const char * ArSerialConnection::getOpenMessage(int messageNumber)
00069 {
00070   return myStrMap[messageNumber].c_str();
00071 }
00072 
00073 AREXPORT int ArSerialConnection::internalOpen(void)
00074 {
00075   struct termios tio;
00076 
00077   if (myStatus == STATUS_OPEN) 
00078   {
00079     ArLog::log(ArLog::Terse, "ArSerialConnection::open: Serial port already open");
00080     return OPEN_ALREADY_OPEN;
00081   }
00082 
00083   /* open the port */
00084   if ((myPort = ::open(myPortName.c_str(),O_RDWR | O_NDELAY)) < 0) 
00085   {
00086     ArLog::log(ArLog::Terse, "ArSerialConnection::open: Could not open serial port '%s'", myPortName.c_str());
00087     return OPEN_COULD_NOT_OPEN_PORT;
00088   }
00089   
00090   /* set the tty baud, buffering and modes */
00091   if (tcgetattr(myPort, &tio) != 0)
00092   {
00093     ArLog::log(ArLog::Terse, "ArSerialConnection::open: Could not get port data to set up port");
00094     close();
00095     myStatus = STATUS_OPEN_FAILED;
00096     return OPEN_COULD_NOT_SET_UP_PORT;
00097   }    
00098 
00099   /* turn off echo, canonical mode, extended processing, signals */
00100   tio.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
00101 
00102   /* turn off break sig, cr->nl, parity off, 8 bit strip, flow control */
00103   tio.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
00104 
00105   /* clear size, turn off parity bit */
00106   tio.c_cflag &= ~(CSIZE | PARENB);
00107 
00108   /* set size to 8 bits */
00109   tio.c_cflag |= CS8;
00110 
00111   /* turn output processing off */
00112   tio.c_oflag &= ~(OPOST);
00113 
00114   /* Set time and bytes to read at once */
00115   tio.c_cc[VTIME] = 0;
00116   tio.c_cc[VMIN] = 0;
00117 
00118   if (tcsetattr(myPort,TCSAFLUSH,&tio) < 0) 
00119   {
00120     ArLog::log(ArLog::Terse, 
00121            "ArSerialConnection::open: Could not set up port");
00122     close();
00123     myStatus = STATUS_OPEN_FAILED;
00124     return OPEN_COULD_NOT_SET_UP_PORT;
00125   }
00126   
00127   myStatus = STATUS_OPEN;
00128 
00129   if (rateToBaud(myBaudRate) == -1) 
00130   {
00131     ArLog::log(ArLog::Terse, "ArSerialConnection::open: Invalid baud rate.");
00132     close();
00133     myStatus = STATUS_OPEN_FAILED;
00134     return OPEN_INVALID_BAUD_RATE;
00135   }
00136 
00137   if (!setBaud(myBaudRate)) 
00138   {
00139     ArLog::log(ArLog::Terse, 
00140            "ArSerialConnection::open: Could not set baud rate.");
00141     close();
00142     myStatus = STATUS_OPEN_FAILED;
00143     return OPEN_COULD_NOT_SET_BAUD;
00144   }
00145   
00146   if (!setHardwareControl(myHardwareControl)) 
00147   {
00148     ArLog::log(ArLog::Terse,
00149            "ArSerialConnection::open: Could not set hardware control.");
00150     close();
00151     myStatus = STATUS_OPEN_FAILED;
00152     return OPEN_COULD_NOT_SET_UP_PORT;
00153   }
00154 
00155   ArLog::log(ArLog::Verbose, "ArSerialConnection::open: Successfully opened and configured serial port.");
00156   return 0;
00157 }
00158 
00159 AREXPORT bool ArSerialConnection::openSimple(void)
00160 {
00161   if (internalOpen() == 0)
00162     return true;
00163   else
00164     return false;
00165 }
00166 
00172 AREXPORT void ArSerialConnection::setPort(const char *port)
00173 {
00174   if (port == NULL)
00175     myPortName = "/dev/ttyS0";
00176   else
00177     myPortName = port;
00178 }
00179 
00183 AREXPORT const char * ArSerialConnection::getPort(void)
00184 {
00185   return myPortName.c_str();
00186 }
00187 
00194 AREXPORT int ArSerialConnection::open(const char *port)
00195 {
00196   setPort(port);
00197   return internalOpen();
00198 }
00199 
00200 AREXPORT bool ArSerialConnection::close(void)
00201 {
00202   int ret;
00203 
00204   myStatus = STATUS_CLOSED_NORMALLY;
00205   if (myPort == -1)
00206     return true;
00207   
00208 
00209   ret = ::close(myPort);
00210 
00211   if (ret == 0)
00212     ArLog::log(ArLog::Verbose,
00213            "ArSerialConnection::close: Successfully closed serial port.");
00214   else
00215     ArLog::log(ArLog::Verbose, 
00216            "ArSerialConnection::close: Unsuccessfully closed serial port.");
00217 
00218   myPort = -1;
00219   if (ret == 0)
00220     return true;
00221   else
00222     return false;
00223 }
00224 
00230 AREXPORT bool ArSerialConnection::setBaud(int rate)
00231 {
00232   struct termios tio;  
00233   int baud;
00234 
00235   myBaudRate = rate;
00236   
00237   if (getStatus() != STATUS_OPEN)
00238     return true;
00239 
00240   if ((baud = rateToBaud(myBaudRate)) == -1)
00241     return false;
00242   
00243   if (tcgetattr(myPort, &tio) != 0)
00244   {
00245     ArLog::log(ArLog::Terse, "ArSerialConnection::setBaud: Could not get port data.");
00246     return false;
00247   }
00248   
00249   if (cfsetospeed(&tio, baud)) 
00250   {
00251     ArLog::log(ArLog::Terse, "ArSerialConnection::setBaud: Could not set output baud rate on termios struct.");
00252     return false;
00253   }
00254        
00255   if (cfsetispeed(&tio, baud)) 
00256   {
00257     ArLog::log(ArLog::Terse, "ArSerialConnection::setBaud: Could not set input baud rate on termios struct.");
00258     return false;
00259   }
00260 
00261   if(tcsetattr(myPort,TCSAFLUSH,&tio) < 0) 
00262   {
00263     ArLog::log(ArLog::Terse, "ArSerialConnection::setBaud: Could not set baud rate.");
00264     return false;
00265   }
00266 
00267   startTimeStamping();
00268   
00269   return true;
00270 }
00271 
00272 AREXPORT void ArSerialConnection::startTimeStamping(void)
00273 {
00274   long baud;
00275   baud = myBaudRate;
00276   if (ioctl(myPort, TIOSTARTTIMESTAMP, &baud) != 0)
00277     myTakingTimeStamps = false;
00278   else
00279     myTakingTimeStamps = true;
00280 }
00281 
00286 AREXPORT int ArSerialConnection::getBaud(void)
00287 {
00288   return myBaudRate;
00289 }
00290 
00291 int ArSerialConnection::rateToBaud(int rate)
00292 {
00293   switch (rate) {
00294   case 300: return B300;
00295   case 1200: return B1200;
00296   case 1800: return B1800;
00297   case 2400: return B2400;
00298   case 4800: return B4800;
00299   case 9600: return B9600;
00300   case 19200: return B19200;
00301   case 38400: return B38400;
00302   case 57600: return B57600;
00303   case 115200: return B115200;
00304   default: 
00305     ArLog::log(ArLog::Terse, "ArSerialConnection::rateToBaud: Did not know baud for rate %d.", rate);
00306     return -1;
00307   }
00308 }
00309 
00310 int ArSerialConnection::baudToRate(int baud)
00311 {
00312   switch (baud) {
00313   case B300: return 300;
00314   case B1200: return 1200;
00315   case B1800: return 1800;
00316   case B2400: return 2400;
00317   case B4800: return 4800;
00318   case B9600: return 9600;
00319   case B19200: return 19200;
00320   case B38400: return 38400;
00321   case B57600: return 57600;
00322   case B115200: return 115200;
00323   default: 
00324     ArLog::log(ArLog::Terse, "ArSerialConnection:baudToRate: Did not know rate for baud.");
00325     return -1;
00326   }
00327   
00328 }
00329 
00335 AREXPORT bool ArSerialConnection::setHardwareControl(bool hardwareControl)
00336 {
00337   struct termios tio;
00338 
00339   myHardwareControl = hardwareControl;
00340 
00341   if (getStatus() != STATUS_OPEN) 
00342     return true;
00343 
00344   tcgetattr(myPort, &tio);
00345 
00346   /* check for hardware flow control */
00347   if (myHardwareControl)
00348     tio.c_cflag |= CRTSCTS;
00349   else
00350     tio.c_cflag &= ~CRTSCTS;
00351       
00352   if(tcsetattr(myPort,TCSAFLUSH,&tio) < 0) {
00353     ArLog::log(ArLog::Terse, "ArSerialConnection::setHardwareControl: Could not set hardware control.");
00354     return false;
00355   }
00356   
00357   return true;
00358 }
00359 
00363 AREXPORT bool ArSerialConnection::getHardwareControl(void)
00364 {
00365   return myHardwareControl;
00366 }
00367 
00368 AREXPORT int ArSerialConnection::write(const char *data, unsigned int size) 
00369 {
00370   int n;
00371   /*
00372   printf("WRITE(%3d): ", size);
00373   for (int i = 0; i < size; i++)
00374     printf("0x%x %c", data[i], data[i]);
00375   printf("\n");
00376   */
00377   if (myPort >= 0) 
00378   {
00379     n = ::write(myPort, data, size);
00380     if (n == -1) 
00381     {
00382       if (errno == EAGAIN)   /* try it again, for USB/serial */
00383     {
00384       usleep(10);
00385       n = ::write(myPort, data, size);
00386       if (n >= 0)
00387         return n;
00388     }
00389       ArLog::log(ArLog::Terse, "ArSerialConnection::write: Error on writing.");
00390       perror("ArSerialConnection::write:");
00391     }
00392     return n;
00393   }
00394   ArLog::log(ArLog::Terse, "ArSerialConnection::write: Connection invalid.");
00395   return -1;
00396 }
00397 
00398 AREXPORT int ArSerialConnection::read(const char *data, unsigned int size,
00399                       unsigned int msWait) 
00400 {
00401   struct timeval tp;        /* time interval structure for timeout */
00402   fd_set fdset;         /* fd set ??? */
00403   int n;
00404   long timeLeft;
00405   unsigned int bytesRead = 0;
00406   ArTime timeDone;
00407 
00408   if (myPort >= 0)
00409   {
00410     if (msWait >= 0)
00411     {
00412       timeDone.setToNow();
00413       timeDone.addMSec(msWait);
00414       while ((timeLeft = timeDone.mSecTo()) >= 0) 
00415       {
00416     tp.tv_sec = (timeLeft) / 1000;  /* we're polling */
00417     tp.tv_usec = (timeLeft % 1000) * 1000;
00418     FD_ZERO(&fdset);
00419     FD_SET(myPort,&fdset);
00420     if (select(myPort+1,&fdset,NULL,NULL,&tp) <= 0) 
00421       return bytesRead;
00422     if ((n = ::read(myPort, const_cast<char *>(data)+bytesRead, 
00423             size-bytesRead)) == -1)
00424     {
00425       ArLog::log(ArLog::Terse, "ArSerialConnection::read:  Blocking read failed.");
00426       return bytesRead;
00427     }
00428     bytesRead += n;
00429     if (bytesRead >= size)
00430       return bytesRead;
00431       }
00432       return bytesRead;
00433     }
00434     else 
00435     {
00436       n = ::read(myPort, const_cast<char *>(data), size);
00437       if (n == -1)
00438     ArLog::log(ArLog::Terse, "ArSerialConnection::read:  Non-Blocking read failed.");
00439       return n;
00440     }
00441   }
00442   ArLog::log(ArLog::Terse, "ArSerialConnection::read:  Connection invalid.");
00443   return -1;
00444 }
00445 
00446 AREXPORT int ArSerialConnection::getStatus(void)
00447 {
00448   return myStatus;
00449 }
00450 
00451 AREXPORT ArTime ArSerialConnection::getTimeRead(int index)
00452 {
00453   ArTime ret;
00454   struct timeval timeStamp;
00455   if (myPort <= 0)
00456   {
00457     ret.setToNow();
00458     return ret;
00459   }
00460 
00461   if (myTakingTimeStamps)
00462   {
00463     timeStamp.tv_sec = index;
00464     if (ioctl(myPort, TIOGETTIMESTAMP, &timeStamp) == 0)
00465     {
00466       ret.setSec(timeStamp.tv_sec);
00467       ret.setMSec(timeStamp.tv_usec / 1000);
00468     }
00469     else
00470       ret.setToNow();
00471   }
00472   else
00473     ret.setToNow();
00474 
00475   return ret;
00476 }
00477 
00478 AREXPORT bool ArSerialConnection::isTimeStamping(void)
00479 {
00480   return myTakingTimeStamps;
00481 }
00482 
00483 
00484 AREXPORT bool ArSerialConnection::getCTS(void)
00485 {
00486   unsigned int value;
00487   if (ioctl(myPort, TIOCMGET, &value) == 0)
00488   {
00489     return (bool) (value & TIOCM_CTS);
00490   }
00491   else
00492   {
00493     perror("ioctl: TIOCMGET");
00494     return false;
00495   }
00496 }
00497 
00498 AREXPORT bool ArSerialConnection::getDSR(void)
00499 {
00500   unsigned int value;
00501   if (ioctl(myPort, TIOCMGET, &value) == 0)
00502   {
00503     return (bool) (value & TIOCM_DSR);
00504   }
00505   else
00506   {
00507     perror("ioctl: TIOCMGET");
00508     return false;
00509   }
00510 }
00511 
00512 AREXPORT bool ArSerialConnection::getDCD(void)
00513 {
00514   unsigned int value;
00515   if (ioctl(myPort, TIOCMGET, &value) == 0)
00516   {
00517     return (bool) (value & TIOCM_CAR);
00518   }
00519   else
00520   {
00521     perror("ioctl: TIOCMGET");
00522     return false;
00523   }
00524 }
00525 
00526 AREXPORT bool ArSerialConnection::getRing(void)
00527 {
00528   unsigned int value;
00529   if (ioctl(myPort, TIOCMGET, &value) == 0)
00530   {
00531     return (bool) (value & TIOCM_RI);
00532   }
00533   else
00534   {
00535     perror("ioctl: TIOCMGET");
00536     return false;
00537   }
00538 }

Generated on Tue Feb 20 10:51:41 2007 for Aria by  doxygen 1.4.0