00001
00002
00003
00004
00005
00006
00007
00008 #include <telekyb_serial/SerialDevice.h>
00009 #include <telekyb_serial/SerialException.h>
00010
00011
00012 #include <sys/file.h>
00013
00014
00015 #include <ros/console.h>
00016
00017 #define INVALID_FD -1
00018
00019 namespace TELEKYB_NAMESPACE
00020 {
00021
00022 SerialDevice::SerialDevice()
00023 : deviceFD(INVALID_FD)
00024 {
00025
00026 }
00027
00028 SerialDevice::SerialDevice(const std::string& deviceName_, bool autoOpen, int oflag)
00029 : deviceName(deviceName_), deviceFD(INVALID_FD)
00030 {
00031
00032 if (autoOpen) {
00033 openDevice(oflag);
00034 }
00035 }
00036
00037 SerialDevice::~SerialDevice()
00038 {
00039 closeDevice();
00040 }
00041
00042 void SerialDevice::openDevice(int oflag)
00043 {
00044
00045 if (isOpen()) {
00046 ROS_WARN_STREAM("Serial Device " << deviceName << "is already open.");
00047
00048 }
00049
00050 try {
00051 if ((deviceFD = open(deviceName.c_str(), oflag)) < 0) {
00052 throw SerialException("Unable to open Serial Device " + deviceName + " !", SerialExceptionCode::UNABLE_TO_OPEN);
00053 }
00054
00055 if (!isatty(deviceFD)) {
00056 throw SerialException("Device " + deviceName + " is not a serial (tty) device.", SerialExceptionCode::NO_TTY);
00057 }
00058
00059 if (flock(deviceFD, LOCK_EX | LOCK_NB) < 0) {
00060
00061 throw SerialException("Unable to open Serial Device " + deviceName + " ! It's locked.",
00062 SerialExceptionCode::LOCKED,
00063 ros::console::levels::Warn);
00064 }
00065
00066 if(tcgetattr(deviceFD, &deviceAttr) < 0 ) {
00067 throw SerialException("Unable get termios attributes of serial device " + deviceName + " !",
00068 SerialExceptionCode::IO_ERROR);
00069 }
00070
00071 } catch (SerialException &e) {
00072
00073
00074 closeDevice();
00075
00076 throw;
00077
00078 }
00079
00080
00081
00082 }
00083
00084 void SerialDevice::closeDevice()
00085 {
00086
00087
00088 if (!isOpen()) {
00089 return;
00090 }
00091
00092 close(deviceFD);
00093 deviceFD = INVALID_FD;
00094 }
00095
00096 bool SerialDevice::isOpen() const
00097 {
00098 return deviceFD != INVALID_FD;
00099 }
00100
00101 bool SerialDevice::readAvailable(timeval timeout) const
00102 {
00103 fd_set readfs;
00104 FD_ZERO(&readfs);
00105 FD_SET(deviceFD, &readfs);
00106
00107 int returnVal = select(deviceFD + 1, &readfs, NULL, NULL, &timeout);
00108
00109
00110
00111 if (returnVal < 0) {
00112 ROS_ERROR("select call failed on %s", deviceName.c_str());
00113 return false;
00114 } else {
00115 return (returnVal > 0);
00116 }
00117
00118 }
00119
00120 int SerialDevice::readDevice(char* buffer, size_t bufferSize, std::string terminalChars) const
00121 {
00122
00123 boost::mutex::scoped_lock lock(readMutex);
00124
00125 int nbytes;
00126 char* bufptr = buffer;
00127
00128
00129 while ((nbytes = read(deviceFD, buffer, buffer + bufferSize - bufptr - 1)) > 0) {
00130 bufptr += nbytes;
00131 if (terminalChars.find(bufptr[-1]) != terminalChars.npos) {
00132
00133 break;
00134 }
00135 }
00136
00137 return (bufptr - buffer);
00138 }
00139
00140 std::ostream& operator<<(std::ostream& stream, const SerialDevice& device)
00141 {
00142
00143 return stream;
00144 }
00145
00146 std::string& operator<<(std::string& string, const SerialDevice& device)
00147 {
00148 char buffer[DEFAULT_BUFFERSIZE];
00149
00150 int nbytes;
00151 do {
00152 nbytes = device.readDevice(buffer, DEFAULT_BUFFERSIZE, "\r\n ");
00153 string.append(buffer, nbytes);
00154 } while (nbytes == DEFAULT_BUFFERSIZE);
00155
00156 return string;
00157 }
00158
00159 int SerialDevice::writeDevice(const void* buffer, size_t size) throw(SerialException)
00160 {
00161
00162
00163 boost::mutex::scoped_lock lock(writeMutex);
00164
00165 int n;
00166 if ((n = write(deviceFD, buffer, size)) < 0) {
00167 ROS_ERROR_STREAM("An error occured while writing to Serial Device "
00168 << deviceName << ". Error ("<< errno << "): " << strerror( errno ));
00169 }
00170
00171
00172 if (n != (signed)size) {
00173
00174 throw SerialException("Wrote less bytes than received! " + deviceName + " !");
00175
00176 }
00177
00178 return n;
00179 }
00180
00181 std::istream& operator>>(std::istream& stream, SerialDevice& device)
00182 {
00183
00184 return stream;
00185 }
00186
00187 std::string& operator>>(std::string& string, SerialDevice& device)
00188 {
00189 char* cString = new char[string.size() + 1];
00190 std::copy(string.begin(), string.end(), cString);
00191 cString[string.size()] = '\0';
00192
00193 device.writeDevice(cString, string.size() + 1);
00194
00195 delete[] cString;
00196 return string;
00197 }
00198
00199 bool SerialDevice::setTermiosAttr(tcflag_t c_iflag, tcflag_t c_oflag, tcflag_t c_cflag, tcflag_t c_lflag,
00200 speed_t ispeed, speed_t ospeed, int optionalOptions)
00201 {
00202 if (!isOpen()) {
00203 ROS_ERROR_STREAM("Unable to set Termios Attributes on Device " << deviceName << ". Not open!");
00204 return false;
00205 }
00206
00207 deviceAttr.c_iflag = c_iflag;
00208 deviceAttr.c_oflag = c_oflag;
00209 deviceAttr.c_cflag = c_cflag;
00210 deviceAttr.c_lflag = c_lflag;
00211
00212 if (ispeed != BUNDEF) {
00213 cfsetispeed(&deviceAttr, ispeed);
00214 }
00215 if (ospeed != BUNDEF) {
00216 cfsetospeed(&deviceAttr, ospeed);
00217 }
00218
00219
00220 if (tcsetattr(deviceFD, optionalOptions, &deviceAttr) < 0) {
00221 ROS_ERROR_STREAM("Unable to set Termios Attributes on Device " << deviceName << ". Closing Device.");
00222 closeDevice();
00223 return false;
00224 }
00225
00226 return true;
00227 }
00228
00229
00230 bool SerialDevice::setTermiosAttrIFlag(tcflag_t c_iflag, int optionalOptions )
00231 {
00232 return setTermiosAttr(
00233 c_iflag,
00234 deviceAttr.c_oflag,
00235 deviceAttr.c_cflag,
00236 deviceAttr.c_lflag,
00237 BUNDEF,
00238 BUNDEF,
00239 optionalOptions
00240 );
00241 }
00242 bool SerialDevice::setTermiosAttrOFlag(tcflag_t c_oflag, int optionalOptions )
00243 {
00244 return setTermiosAttr(
00245 deviceAttr.c_iflag,
00246 c_oflag,
00247 deviceAttr.c_cflag,
00248 deviceAttr.c_lflag,
00249 BUNDEF,
00250 BUNDEF,
00251 optionalOptions
00252 );
00253 }
00254 bool SerialDevice::setTermiosAttrCFlag(tcflag_t c_cflag, int optionalOptions )
00255 {
00256 return setTermiosAttr(
00257 deviceAttr.c_iflag,
00258 deviceAttr.c_oflag,
00259 c_cflag,
00260 deviceAttr.c_lflag,
00261 BUNDEF,
00262 BUNDEF,
00263 optionalOptions
00264 );
00265 }
00266 bool SerialDevice::setTermiosAttrLFlag(tcflag_t c_lflag, int optionalOptions )
00267 {
00268 return setTermiosAttr(
00269 deviceAttr.c_iflag,
00270 deviceAttr.c_oflag,
00271 deviceAttr.c_cflag,
00272 c_lflag,
00273 BUNDEF,
00274 BUNDEF,
00275 optionalOptions
00276 );
00277 }
00278 bool SerialDevice::setTermiosAttrSpeed(speed_t ispeed, speed_t ospeed, int optionalOptions )
00279 {
00280 return setTermiosAttr(
00281 deviceAttr.c_iflag,
00282 deviceAttr.c_oflag,
00283 deviceAttr.c_cflag,
00284 deviceAttr.c_lflag,
00285 ispeed,
00286 ospeed,
00287 optionalOptions
00288 );
00289 }
00290
00291 void SerialDevice::printTermiosAttr() const
00292 {
00293 if (!isOpen()) {
00294 ROS_ERROR_STREAM("Unable to print Termios Attributes. Device " << deviceName << " not open!");
00295 return;
00296 }
00297
00298
00299 std::cout << "Look up Meaning: http://dce.felk.cvut.cz/pos/cv5/doc/serial.html" << std::endl;
00300 std::cout << std::endl;
00301 std::cout << "c_iflag (" << deviceAttr.c_iflag << "): ";
00302 std::cout << "IGNBRK(" << ((deviceAttr.c_iflag & IGNBRK) == IGNBRK) << ") ";
00303 std::cout << "BRKINT(" << ((deviceAttr.c_iflag & BRKINT) == BRKINT) << ") ";
00304 std::cout << "IGNPAR(" << ((deviceAttr.c_iflag & IGNPAR) == IGNPAR) << ") ";
00305 std::cout << "PARMRK(" << ((deviceAttr.c_iflag & PARMRK) == PARMRK) << ") ";
00306 std::cout << "INPCK(" << ((deviceAttr.c_iflag & INPCK) == INPCK) << ") ";
00307 std::cout << "ISTRIP(" << ((deviceAttr.c_iflag & ISTRIP) == ISTRIP) << ") ";
00308 std::cout << "INLCR(" << ((deviceAttr.c_iflag & INLCR) == INLCR) << ") ";
00309 std::cout << "IGNCR(" << ((deviceAttr.c_iflag & IGNCR) == IGNCR) << ") ";
00310 std::cout << "ICRNL(" << ((deviceAttr.c_iflag & ICRNL) == ICRNL) << ") ";
00311 #ifndef __APPLE__
00312 std::cout << "IUCLC(" << ((deviceAttr.c_iflag & IUCLC) == IUCLC) << ") ";
00313 #endif
00314 std::cout << "IXON(" << ((deviceAttr.c_iflag & IXON) == IXON) << ") ";
00315 std::cout << "IXANY(" << ((deviceAttr.c_iflag & IXANY) == IXANY) << ") ";
00316 std::cout << "IXOFF(" << ((deviceAttr.c_iflag & IXOFF) == IXOFF) << ") ";
00317 std::cout << "IMAXBEL(" << ((deviceAttr.c_iflag & IMAXBEL) == IMAXBEL) << ") ";
00318 std::cout << "IUTF8(" << ((deviceAttr.c_iflag & IUTF8) == IUTF8) << ") ";
00319 std::cout << std::endl;;
00320 std::cout << "------------------------" << std::endl;
00321
00322 std::cout << "c_oflag (" << deviceAttr.c_oflag << "): ";
00323
00324 std::cout << "OPOST(" << ((deviceAttr.c_oflag & OPOST) == OPOST) << ") ";
00325 #ifndef __APPLE__
00326 std::cout << "OLCUC(" << ((deviceAttr.c_oflag & OLCUC) == OLCUC) << ") ";
00327 #endif
00328 std::cout << "ONLCR(" << ((deviceAttr.c_oflag & ONLCR) == ONLCR) << ") ";
00329 std::cout << "OCRNL(" << ((deviceAttr.c_oflag & OCRNL) == OCRNL) << ") ";
00330 std::cout << "ONOCR(" << ((deviceAttr.c_oflag & ONOCR) == ONOCR) << ") ";
00331 std::cout << "ONLRET(" << ((deviceAttr.c_oflag & ONLRET) == ONLRET) << ") ";
00332 std::cout << "OFILL(" << ((deviceAttr.c_oflag & OFILL) == OFILL) << ") ";
00333 std::cout << "OFDEL(" << ((deviceAttr.c_oflag & OFDEL) == OFDEL) << ") ";
00334 #if defined __USE_MISC || defined __USE_XOPEN
00335
00336 std::cout << " NL0(" << ((deviceAttr.c_oflag & NLDLY) == NL0) << ") ";
00337 std::cout << " NL1(" << ((deviceAttr.c_oflag & NLDLY) == NL1) << ") ";
00338
00339 std::cout << " CR0(" << ((deviceAttr.c_oflag & CRDLY) == CR0) << ") ";
00340 std::cout << " CR1(" << ((deviceAttr.c_oflag & CRDLY) == CR1) << ") ";
00341 std::cout << " CR2(" << ((deviceAttr.c_oflag & CRDLY) == CR2) << ") ";
00342 std::cout << " CR3(" << ((deviceAttr.c_oflag & CRDLY) == CR3) << ") ";
00343
00344 std::cout << " TAB0(" << ((deviceAttr.c_oflag & TABDLY) == TAB0) << ") ";
00345 std::cout << " TAB1(" << ((deviceAttr.c_oflag & TABDLY) == TAB1) << ") ";
00346 std::cout << " TAB2(" << ((deviceAttr.c_oflag & TABDLY) == TAB2) << ") ";
00347 std::cout << " TAB3(" << ((deviceAttr.c_oflag & TABDLY) == TAB3) << ") ";
00348
00349 std::cout << " BS0(" << ((deviceAttr.c_oflag & BSDLY) == BS0) << ") ";
00350 std::cout << " BS1(" << ((deviceAttr.c_oflag & BSDLY) == BS1) << ") ";
00351
00352 std::cout << " FF0(" << ((deviceAttr.c_oflag & FFDLY) == FF0) << ") ";
00353 std::cout << " FF1(" << ((deviceAttr.c_oflag & FFDLY) == FF1) << ") ";
00354 #endif
00355 std::cout << std::endl;
00356
00357
00358 std::cout << "------------------------" << std::endl;
00359
00360 std::cout << "c_cflag (" << deviceAttr.c_cflag << "): ";
00361
00362 #ifndef __APPLE__
00363 std::cout << "B0(" << ((deviceAttr.c_cflag & CBAUD) == B0) << ") ";
00364 std::cout << "B50(" << ((deviceAttr.c_cflag & CBAUD) == B50) << ") ";
00365 std::cout << "B75(" << ((deviceAttr.c_cflag & CBAUD) == B75) << ") ";
00366 std::cout << "B110(" << ((deviceAttr.c_cflag & CBAUD) == B110) << ") ";
00367 std::cout << "B134(" << ((deviceAttr.c_cflag & CBAUD) == B134) << ") ";
00368 std::cout << "B150(" << ((deviceAttr.c_cflag & CBAUD) == B150) << ") ";
00369 std::cout << "B200(" << ((deviceAttr.c_cflag & CBAUD) == B200) << ") ";
00370 std::cout << "B300(" << ((deviceAttr.c_cflag & CBAUD) == B300) << ") ";
00371 std::cout << "B600(" << ((deviceAttr.c_cflag & CBAUD) == B600) << ") ";
00372 std::cout << "B1200(" << ((deviceAttr.c_cflag & CBAUD) == B1200) << ") ";
00373 std::cout << "B1800(" << ((deviceAttr.c_cflag & CBAUD) == B1800) << ") ";
00374 std::cout << "B2400(" << ((deviceAttr.c_cflag & CBAUD) == B2400) << ") ";
00375 std::cout << "B4800(" << ((deviceAttr.c_cflag & CBAUD) == B4800) << ") ";
00376 std::cout << "B9600(" << ((deviceAttr.c_cflag & CBAUD) == B9600) << ") ";
00377 std::cout << "B19200(" << ((deviceAttr.c_cflag & CBAUD) == B19200) << ") ";
00378 std::cout << "B38400(" << ((deviceAttr.c_cflag & CBAUD) == B38400) << ") ";
00379 std::cout << "B57600(" << ((deviceAttr.c_cflag & CBAUD) == B57600) << ") ";
00380 std::cout << "B115200(" << ((deviceAttr.c_cflag & CBAUD) == B115200) << ") ";
00381 std::cout << "B230400(" << ((deviceAttr.c_cflag & CBAUD) == B230400) << ") ";
00382 std::cout << "B460800(" << ((deviceAttr.c_cflag & CBAUD) == B460800) << ") ";
00383 std::cout << "B500000(" << ((deviceAttr.c_cflag & CBAUD) == B500000) << ") ";
00384 std::cout << "B576000(" << ((deviceAttr.c_cflag & CBAUD) == B576000) << ") ";
00385 std::cout << "B921600(" << ((deviceAttr.c_cflag & CBAUD) == B921600) << ") ";
00386 std::cout << "B1000000(" << ((deviceAttr.c_cflag & CBAUD) == B1000000) << ") ";
00387 std::cout << "B1152000(" << ((deviceAttr.c_cflag & CBAUD) == B1152000) << ") ";
00388 std::cout << "B1500000(" << ((deviceAttr.c_cflag & CBAUD) == B1500000) << ") ";
00389 std::cout << "B2000000(" << ((deviceAttr.c_cflag & CBAUD) == B2000000) << ") ";
00390 std::cout << "B2500000(" << ((deviceAttr.c_cflag & CBAUD) == B2500000) << ") ";
00391 std::cout << "B3000000(" << ((deviceAttr.c_cflag & CBAUD) == B3000000) << ") ";
00392 std::cout << "B3500000(" << ((deviceAttr.c_cflag & CBAUD) == B3500000) << ") ";
00393 std::cout << "B4000000(" << ((deviceAttr.c_cflag & CBAUD) == B4000000) << ") ";
00394 #endif
00395
00396
00397 std::cout << "CS5(" << ((deviceAttr.c_cflag & CSIZE) == CS5) << ") ";
00398 std::cout << "CS6(" << ((deviceAttr.c_cflag & CSIZE) == CS6) << ") ";
00399 std::cout << "CS7(" << ((deviceAttr.c_cflag & CSIZE) == CS7) << ") ";
00400 std::cout << "CS8(" << ((deviceAttr.c_cflag & CSIZE) == CS8) << ") ";
00401 std::cout << "CSTOPB(" << ((deviceAttr.c_cflag & CSTOPB) == CSTOPB) << ") ";
00402 std::cout << "CREAD(" << ((deviceAttr.c_cflag & CREAD) == CREAD) << ") ";
00403 std::cout << "PARENB(" << ((deviceAttr.c_cflag & PARENB) == PARENB) << ") ";
00404 std::cout << "PARODD(" << ((deviceAttr.c_cflag & PARODD) == PARODD) << ") ";
00405 std::cout << "HUPCL(" << ((deviceAttr.c_cflag & HUPCL) == HUPCL) << ") ";
00406 std::cout << "CLOCAL(" << ((deviceAttr.c_cflag & CLOCAL) == CLOCAL) << ") ";
00407 #ifdef __USE_MISC
00408 std::cout << "CBAUDEX(" << ((deviceAttr.c_cflag & CBAUDEX) == CBAUDEX) << ") ";
00409 #endif
00410
00411 #ifdef __USE_MISC
00412 std::cout << "CIBAUD(" << ((deviceAttr.c_cflag & CIBAUD) == CIBAUD) << ") ";
00413 std::cout << "CMSPAR(" << ((deviceAttr.c_cflag & CMSPAR) == CMSPAR) << ") ";
00414 std::cout << "CRTSCTS(" << ((deviceAttr.c_cflag & CRTSCTS) == CRTSCTS) << ") ";
00415 #endif
00416
00417 std::cout << std::endl;
00418 speed_t ispeed = cfgetispeed(&deviceAttr);
00419 speed_t ospeed = cfgetospeed(&deviceAttr);
00420 std::cout << "BAUD Rate (IN): " << ispeed << " " << "BAUD Rate (OUT): " << ospeed << std::endl;
00421 std::cout << "------------------------" << std::endl;
00422
00423 std::cout << "c_lflag (" << deviceAttr.c_lflag << "): ";
00424 std::cout << "ISIG(" << ((deviceAttr.c_lflag & ISIG) == ISIG) << ") ";
00425 std::cout << "ICANON(" << ((deviceAttr.c_lflag & ICANON) == ICANON) << ") ";
00426 #if defined __USE_MISC || defined __USE_XOPEN
00427 std::cout << "XCASE(" << ((deviceAttr.c_lflag & XCASE) == XCASE) << ") ";
00428 #endif
00429 std::cout << "ECHO(" << ((deviceAttr.c_lflag & ECHO) == ECHO) << ") ";
00430 std::cout << "ECHOE(" << ((deviceAttr.c_lflag & ECHOE) == ECHOE) << ") ";
00431 std::cout << "ECHOK(" << ((deviceAttr.c_lflag & ECHOK) == ECHOK) << ") ";
00432 std::cout << "ECHONL(" << ((deviceAttr.c_lflag & ECHONL) == ECHONL) << ") ";
00433 std::cout << "NOFLSH(" << ((deviceAttr.c_lflag & NOFLSH) == NOFLSH) << ") ";
00434 std::cout << "TOSTOP(" << ((deviceAttr.c_lflag & TOSTOP) == TOSTOP) << ") ";
00435 #ifdef __USE_MISC
00436 std::cout << "ECHOCTL(" << ((deviceAttr.c_lflag & ECHOCTL) == ECHOCTL) << ") ";
00437 std::cout << "ECHOPRT(" << ((deviceAttr.c_lflag & ECHOPRT) == ECHOPRT) << ") ";
00438 std::cout << "ECHOKE(" << ((deviceAttr.c_lflag & ECHOKE) == ECHOKE) << ") ";
00439 std::cout << "FLUSHO(" << ((deviceAttr.c_lflag & FLUSHO) == FLUSHO) << ") ";
00440 std::cout << "PENDIN(" << ((deviceAttr.c_lflag & PENDIN) == PENDIN) << ") ";
00441 #endif
00442 std::cout << "IEXTEN(" << ((deviceAttr.c_lflag & IEXTEN) == IEXTEN) << ") ";
00443 #ifdef __USE_BSD
00444 std::cout << "EXTPROC(" << ((deviceAttr.c_lflag & EXTPROC) == EXTPROC) << ") ";
00445 #endif
00446 std::cout << std::endl;
00447 std::cout << "------------------------" << std::endl;
00448
00449
00450
00451 }
00452
00453 }