00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
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
00100 tio.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
00101
00102
00103 tio.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
00104
00105
00106 tio.c_cflag &= ~(CSIZE | PARENB);
00107
00108
00109 tio.c_cflag |= CS8;
00110
00111
00112 tio.c_oflag &= ~(OPOST);
00113
00114
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
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
00373
00374
00375
00376
00377 if (myPort >= 0)
00378 {
00379 n = ::write(myPort, data, size);
00380 if (n == -1)
00381 {
00382 if (errno == EAGAIN)
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;
00402 fd_set fdset;
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;
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 }