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

ArSerialConnection_LIN.cpp

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

Generated on Wed Oct 19 12:56:36 2005 for Aria by  doxygen 1.4.0