00001 /*!@file Devices/SerialAdvanced.C A class for interfacing with a serial port */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Randolph Voorhies <voorhies at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/SerialAdvanced.C $ 00035 // $Id: SerialAdvanced.C 13712 2010-07-28 21:00:40Z itti $ 00036 // 00037 00038 #include "Devices/SerialAdvanced.H" 00039 00040 #include "Component/OptionManager.H" 00041 #include "Util/log.H" 00042 #include "rutz/unixcall.h" // for rutz::unixcall::get_file_user_pid() 00043 00044 #include <iostream> 00045 00046 const ModelOptionCateg MOC_SerialAdvanced = { 00047 MOC_SORTPRI_3, "Advanced Serial Port Related Options" }; 00048 00049 const ModelOptionDef OPT_DevNameAdvanced = 00050 { MODOPT_ARG(std::string), "DevNameAdvanced", &MOC_SerialAdvanced, OPTEXP_CORE, 00051 "Device file", 00052 "serial-dev-advanced", '\0', "", "/dev/ttyS0" }; 00053 00054 const ModelOptionDef OPT_Baud = 00055 { MODOPT_ARG(int), "Baud", &MOC_SerialAdvanced, OPTEXP_CORE, 00056 "Baud Rate", 00057 "serial-baud", '\0', "", "9600" }; 00058 00059 const ModelOptionDef OPT_CharBits = 00060 { MODOPT_ARG(int), "CharBits", &MOC_SerialAdvanced, OPTEXP_CORE, 00061 "Number of bits per character", 00062 "serial-charbits", '\0', "", "8" }; 00063 00064 const ModelOptionDef OPT_StopBits = 00065 { MODOPT_ARG(int), "StopBits", &MOC_SerialAdvanced, OPTEXP_CORE, 00066 "Number of stop bits", 00067 "serial-stopbits", '\0', "", "1" }; 00068 00069 const ModelOptionDef OPT_UseParity = 00070 { MODOPT_ARG(bool), "UseParity", &MOC_SerialAdvanced, OPTEXP_CORE, 00071 "Use Parity?", 00072 "serial-parity", '\0', "true | false", "false" }; 00073 00074 const ModelOptionDef OPT_ParityOdd = 00075 { MODOPT_ARG(bool), "ParityOdd", &MOC_SerialAdvanced, OPTEXP_CORE, 00076 "Use Odd Parity?", 00077 "serial-oddparity", '\0', "true | false", "false" }; 00078 00079 const ModelOptionDef OPT_FlowHard = 00080 { MODOPT_ARG(bool), "FlowHard", &MOC_SerialAdvanced, OPTEXP_CORE, 00081 "Use Hardware Flow Control?", 00082 "serial-flowhard", '\0', "true | false", "false" }; 00083 00084 const ModelOptionDef OPT_FlowSoft = 00085 { MODOPT_ARG(bool), "FlowSoft", &MOC_SerialAdvanced, OPTEXP_CORE, 00086 "Use Software Flow Control?", 00087 "serial-flowsoft", '\0', "true | false", "false" }; 00088 00089 const ModelOptionDef OPT_RdTout = 00090 { MODOPT_ARG(int), "RdTout", &MOC_SerialAdvanced, OPTEXP_CORE, 00091 "Read Timeout", 00092 "serial-readtout", '\0', "", "-1" }; 00093 00094 const ModelOptionDef OPT_Blocking = 00095 { MODOPT_ARG(bool), "Blocking", &MOC_SerialAdvanced, OPTEXP_CORE, 00096 "Use Blocking Mode?", 00097 "serial-blocking", '\0', "true | false", "true" }; 00098 00099 const ModelOptionDef OPT_DevSearchDescriptor = 00100 { MODOPT_ARG(std::string), "DevSearchDesctriptor", &MOC_SerialAdvanced, OPTEXP_CORE, 00101 "Some of the serial devices in iLab will respond to a command of '0' with " 00102 "a framed string containing a device description. By setting this commmand line option, " 00103 "one can specify which such string to search for among all available serial devices. " 00104 "The DevName will then be set according to which available device with the correct string.", 00105 "dev-descriptor", '\0', "", "" }; 00106 00107 // ###################################################################### 00108 00109 SerialAdvanced::SerialAdvanced(OptionManager& mgr, 00110 const std::string& descrName, 00111 const std::string& tagName) : 00112 ModelComponent(mgr, descrName, tagName), 00113 dev(-1), serialErrno(serialErrSuccess), 00114 itsDevName(&OPT_DevNameAdvanced, this,0), 00115 itsBaud(&OPT_Baud, this, 0), 00116 itsCharBits(&OPT_CharBits, this, 0), 00117 itsStopBits(&OPT_StopBits, this, 0), 00118 itsUseParity(&OPT_UseParity, this, 0), 00119 itsParityOdd(&OPT_ParityOdd, this, 0), 00120 itsFlowHard(&OPT_FlowHard, this, 0), 00121 itsFlowSoft(&OPT_FlowSoft, this, 0), 00122 itsRdTout(&OPT_RdTout, this, 0), 00123 itsBlocking(&OPT_Blocking, this, 0), 00124 itsDevSearchDescriptor(&OPT_DevSearchDescriptor, this, 0) 00125 { } 00126 00127 // ###################################################################### 00128 void SerialAdvanced::start2() 00129 { 00130 serialErrno = serialErrSuccess; // clear the error flag 00131 00132 openPort(); // open the device 00133 perror(); 00134 00135 setSpeed(itsBaud.getVal()); // Set the baud rate 00136 perror(); 00137 00138 setFlowControl(itsFlowHard.getVal(), 00139 itsFlowSoft.getVal()); // Set flow control 00140 perror(); 00141 00142 setCharBits(itsCharBits.getVal()); // set no of bits in a char 00143 perror(); 00144 00145 setParity(itsUseParity.getVal(), 00146 itsParityOdd.getVal()); // Set even or odd parity 00147 perror(); 00148 00149 setBlocking(itsBlocking.getVal()); // blocking mode? 00150 perror(); 00151 } 00152 00153 #include <cstdio> 00154 // ###################################################################### 00155 void SerialAdvanced::stop2() 00156 { 00157 if(dev >= 0) { 00158 //sendBreak(); 00159 fputs("closing...\n", stderr); 00160 close(dev); 00161 dev = -1; } 00162 } 00163 00164 // ###################################################################### 00165 void SerialAdvanced::configure(const char *dev, const int speed, const char *format, 00166 const bool flowSoft, const bool flowHard, 00167 const int tout) 00168 { 00169 itsDevName.setVal(dev); 00170 itsBaud.setVal(speed); 00171 itsFlowSoft.setVal(flowSoft); 00172 itsFlowHard.setVal(flowHard); 00173 itsRdTout.setVal(tout); 00174 00175 if (strlen(format) != 3) LFATAL("Incorrect format string: %s", format); 00176 00177 switch(format[0]) { 00178 case '5': itsCharBits.setVal(5); break; 00179 case '6': itsCharBits.setVal(6); break; 00180 case '7': itsCharBits.setVal(7); break; 00181 case '8': itsCharBits.setVal(8); break; 00182 default: LFATAL("Invalid charbits: %c (should be 5..8)", format[0]); 00183 } 00184 00185 switch(format[1]) { 00186 case 'N': itsUseParity.setVal(false); break; 00187 case 'E': itsUseParity.setVal(true); itsParityOdd.setVal(false); break; 00188 case 'O': itsUseParity.setVal(true); itsParityOdd.setVal(true); break; 00189 default: LFATAL("Invalid parity: %c (should be N,E,O)", format[1]); 00190 } 00191 00192 switch(format[2]) { 00193 case '1': itsStopBits.setVal(1); break; 00194 case '2': itsStopBits.setVal(2); break; 00195 default: LFATAL("Invalid stopbits: %c (should be 1..2)", format[2]); 00196 } 00197 } 00198 00199 // ###################################################################### 00200 serialError SerialAdvanced::setSpeed(const int speed) 00201 { 00202 struct termios options; 00203 unsigned int rate; 00204 00205 switch(speed) 00206 { 00207 case 115200: 00208 rate = B115200; 00209 break; 00210 case 57600: 00211 rate = B57600; 00212 break; 00213 case 38400: 00214 rate = B38400; 00215 break; 00216 case 19200: 00217 rate = B19200; 00218 break; 00219 case 9600: 00220 rate = B9600; 00221 break; 00222 case 4800: 00223 rate = B4800; 00224 break; 00225 case 2400: 00226 rate = B2400; 00227 break; 00228 case 1200: 00229 rate = B1200; 00230 break; 00231 case 600: 00232 rate = B600; 00233 break; 00234 case 300: 00235 rate = B300; 00236 break; 00237 case 110: 00238 rate = B110; 00239 break; 00240 case 0: 00241 rate = B0; 00242 break; 00243 default: 00244 return serialError(serialErrSpeedInvalid); 00245 } 00246 00247 // get current options 00248 if(tcgetattr(dev, &options)==-1){ 00249 serialErrno = serialErrTcGetAttrFailed; 00250 return serialErrno; 00251 } 00252 00253 // set the speed 00254 cfsetispeed(&options, rate); 00255 cfsetospeed(&options, rate); 00256 00257 // change the terminals parameter instantly 00258 if( tcsetattr(dev, TCSANOW, &options) == -1){ 00259 serialErrno = serialErrTcSetAttrFailed; 00260 return serialErrno; 00261 } 00262 00263 if( tcgetattr(dev, &options) == -1) { 00264 serialErrno = serialErrTcGetAttrFailed; 00265 return serialErrno; 00266 } 00267 00268 // update our ModelParam: 00269 itsBaud.setVal(speed); 00270 00271 return serialErrSuccess; 00272 } 00273 00274 00275 // ###################################################################### 00276 serialError SerialAdvanced::setFlowControl(const bool useHard, const bool useSoft) 00277 { 00278 termios options; 00279 00280 if( tcgetattr(dev, &options) == -1){ 00281 serialErrno = serialErrTcGetAttrFailed; 00282 return serialErrno; 00283 } 00284 00285 options.c_cflag &= ~CRTSCTS; 00286 options.c_iflag &= ~(IXON | IXANY | IXOFF); 00287 00288 if (useSoft) options.c_iflag |= (IXON | IXANY | IXOFF); 00289 if (useHard) options.c_cflag |= CRTSCTS; 00290 00291 if(tcsetattr(dev, TCSANOW, &options) == -1){ 00292 serialErrno = serialErrTcGetAttrFailed; 00293 return serialErrno; 00294 } 00295 00296 // update our ModelParams: 00297 itsFlowHard.setVal(useHard); 00298 itsFlowSoft.setVal(useSoft); 00299 00300 return serialErrSuccess; 00301 } 00302 00303 // ###################################################################### 00304 serialError SerialAdvanced::setCharBits(const int bits) 00305 { 00306 termios options; 00307 00308 if(tcgetattr(dev, &options)==-1){ 00309 serialErrno = serialErrTcGetAttrFailed; 00310 return serialErrno; 00311 } 00312 00313 options.c_cflag &= ~CSIZE; // mask off the 'size' bits 00314 00315 switch(bits) 00316 { 00317 case 5: options.c_cflag |= CS5; break; 00318 case 6: options.c_cflag |= CS6; break; 00319 case 7: options.c_cflag |= CS7; break; 00320 case 8: options.c_cflag |= CS8; break; 00321 default: return serialError(serialErrCharsizeInvalid); 00322 } 00323 00324 if( tcsetattr(dev, TCSANOW, &options) == -1 ){ 00325 serialErrno = serialErrTcSetAttrFailed; 00326 return serialErrno; 00327 } 00328 00329 // update our ModelParam: 00330 itsCharBits.setVal(bits); 00331 00332 return serialErrSuccess; 00333 } 00334 00335 // ###################################################################### 00336 serialError SerialAdvanced::setParity(const bool useParity, const bool oddParity) 00337 { 00338 struct termios options; 00339 00340 if(tcgetattr(dev, &options)==-1){ 00341 serialErrno = serialErrTcGetAttrFailed; 00342 return serialErrno; 00343 } 00344 00345 options.c_cflag &= ~(PARENB | PARODD); 00346 if (useParity) 00347 { 00348 if (oddParity) 00349 options.c_cflag |= (PARENB | PARODD); 00350 else 00351 options.c_cflag |= PARENB; 00352 } 00353 00354 if(tcsetattr(dev, TCSANOW, &options) == -1){ 00355 serialErrno = serialErrTcSetAttrFailed; 00356 return serialErrno; 00357 } 00358 00359 // update our ModelParams: 00360 itsUseParity.setVal(useParity); 00361 itsParityOdd.setVal(oddParity); 00362 00363 return serialErrSuccess; 00364 } 00365 00366 // ###################################################################### 00367 serialError SerialAdvanced::setStopBits(const int bits) 00368 { 00369 struct termios options; 00370 00371 if(tcgetattr(dev, &options)==-1){ 00372 serialErrno = serialErrTcGetAttrFailed; 00373 return serialErrno; 00374 } 00375 00376 options.c_cflag &= ~CSTOPB; 00377 if (bits == 2) options.c_cflag |= CSTOPB; 00378 else if (bits != 1) return serialError(serialErrStopbitsInvalid); 00379 00380 if(tcsetattr(dev, TCSANOW, &options) == -1){ 00381 serialErrno = serialErrTcSetAttrFailed; 00382 return serialErrno; 00383 } 00384 00385 // update our ModelParam: 00386 itsStopBits.setVal(bits); 00387 00388 return serialErrSuccess; 00389 } 00390 00391 // ###################################################################### 00392 serialError SerialAdvanced::setBlocking(const bool blocking) 00393 { 00394 int flags = fcntl(dev, F_GETFL, 0); 00395 if (flags == -1) PLERROR("Cannot get flags"); 00396 if (blocking) flags &= (~O_NONBLOCK); else flags |= O_NONBLOCK; 00397 if (fcntl(dev, F_SETFL, flags) == -1) PLERROR("Cannot set flags"); 00398 00399 itsBlocking.setVal(blocking); 00400 00401 return serialErrSuccess; 00402 } 00403 00404 // ###################################################################### 00405 void SerialAdvanced::toggleDTR(const time_t ms) 00406 { 00407 struct termios tty, old; 00408 if(tcgetattr(dev, &tty) == -1 || tcgetattr(dev, &old) == -1){ 00409 serialErrno = serialErrTcGetAttrFailed; 00410 } 00411 00412 cfsetospeed(&tty, B0); 00413 cfsetispeed(&tty, B0); 00414 00415 if(tcsetattr(dev, TCSANOW, &tty) == -1){ 00416 serialErrno = serialErrTcSetAttrFailed; 00417 } 00418 00419 if(ms) 00420 usleep(ms*1000); 00421 00422 if(tcsetattr(dev, TCSANOW, &old) == -1){ 00423 serialErrno = serialErrTcSetAttrFailed; 00424 } 00425 } 00426 00427 // ###################################################################### 00428 void SerialAdvanced::sendBreak(void) 00429 { 00430 // Send a Hangup to the port 00431 tcsendbreak(dev, 0); 00432 } 00433 00434 // ###################################################################### 00435 serialError SerialAdvanced::error(const serialError serialErrorNum) 00436 { 00437 serialErrno = serialErrorNum; 00438 return serialErrorNum; 00439 } 00440 00441 // ###################################################################### 00442 int SerialAdvanced::openPort() 00443 { 00444 const pid_t fuser = 00445 rutz::unixcall::get_file_user_pid(itsDevName.getVal().c_str()); 00446 00447 if (fuser != 0 && itsDevName.getVal().compare("/dev/null") != 0) 00448 { 00449 LFATAL("serial device %s is already in use by process pid=%d;\n" 00450 "\ttry using /dev/null or a different serial device instead", 00451 itsDevName.getVal().c_str(), int(fuser)); 00452 } 00453 00454 int flags= O_RDWR | O_NOCTTY; 00455 termios options; 00456 00457 // don't set the flag if we are setting a timeout on 00458 // the descriptor 00459 if (itsRdTout.getVal() < 0) flags |= O_NDELAY; 00460 00461 CLDEBUG("Opening port %s", itsDevName.getVal().c_str()); 00462 dev = ::open(itsDevName.getVal().c_str(), flags); 00463 if (dev == -1) { serialErrno = serialErrOpenFailed; return dev; } 00464 LDEBUG("Done"); 00465 00466 // Save current state 00467 if( tcgetattr(dev, &savedState) == -1 ){ 00468 serialErrno = serialErrTcGetAttrFailed; 00469 return -1; 00470 } 00471 00472 // reset all the flags 00473 if( fcntl(dev, F_SETFL, 0) == -1 ){ 00474 serialErrno = serialErrFcntlFailed; 00475 return -1; 00476 } 00477 00478 if(tcgetattr(dev, &options) == -1 ){ 00479 serialErrno = serialErrTcGetAttrFailed; 00480 return -1; 00481 } 00482 00483 // get raw input from the port 00484 options.c_cflag |= ( CLOCAL // ignore modem control lines 00485 | CREAD ); // enable the receiver 00486 00487 options.c_iflag &= ~( IGNBRK // ignore BREAK condition on input 00488 | BRKINT // If IGNBRK is not set, generate SIGINT 00489 // on BREAK condition, else read BREAK as \0 00490 | PARMRK 00491 | ISTRIP // strip off eighth bit 00492 | INLCR // donot translate NL to CR on input 00493 | IGNCR // ignore CR 00494 | ICRNL // translate CR to newline on input 00495 | IXON // disable XON/XOFF flow control on output 00496 ); 00497 00498 // disable implementation-defined output processing 00499 options.c_oflag &= ~OPOST; 00500 options.c_lflag &= ~(ECHO // dont echo i/p chars 00501 | ECHONL // do not echo NL under any circumstance 00502 | ICANON // disable cannonical mode 00503 | ISIG // do not signal for INTR, QUIT, SUSP etc 00504 | IEXTEN // disable platform dependent i/p processing 00505 ); 00506 00507 // set a timeout on the descriptor 00508 if(itsRdTout.getVal() > 0) { 00509 options.c_cc[VMIN] = 0; 00510 options.c_cc[VTIME] = itsRdTout.getVal(); 00511 } 00512 00513 if( tcsetattr(dev, TCSANOW, &options) == -1){ 00514 serialErrno = serialErrTcSetAttrFailed; 00515 return -1; 00516 } 00517 return dev; 00518 } 00519 00520 00521 // ###################################################################### 00522 int SerialAdvanced::read(void* buffer, const int nbytes) 00523 { 00524 int n = ::read(dev, buffer, nbytes); 00525 00526 if(n==-1) 00527 serialErrno = serialErrReadFailed; 00528 00529 if(n==0) 00530 serialErrno = serialErrReadTimedOut; 00531 00532 return n; 00533 } 00534 00535 00536 // ###################################################################### 00537 char SerialAdvanced::read(void) 00538 { 00539 char ch; 00540 00541 this->read(&ch, 1); 00542 00543 return ch; 00544 } 00545 00546 00547 // ###################################################################### 00548 int SerialAdvanced::write(const void* buffer, const int nbytes) 00549 { 00550 //char c[3] = { 0xff, 0x01, 0xff }; 00551 //::write(dev, c, 3); 00552 00553 int n = ::write(dev, buffer, nbytes); 00554 00555 /* 00556 //LINFO("----------------- WRITE --------------------"); 00557 for(int i=0; i<n; ++i) 00558 { 00559 fprintf(stderr, "%02X ", 00560 (static_cast<const unsigned char*>(buffer)[i])&0xff); 00561 } 00562 fprintf(stderr,"\n"); 00563 //LINFO("-------------------------------------------"); 00564 */ 00565 00566 if(n==-1) 00567 serialErrno = serialErrWriteFailed; 00568 00569 return n; 00570 } 00571 00572 00573 // ###################################################################### 00574 void SerialAdvanced::perror(void) 00575 { 00576 const char* s=NULL; // initialize to stop g++ from complaining! 00577 switch(serialErrno) 00578 { 00579 case serialErrSuccess: 00580 s = "Success"; 00581 return; 00582 case serialErrOpenNoTty: 00583 s = "SerialAdvanced::Open() No TTY Failed"; 00584 break; 00585 case serialErrOpenFailed: 00586 s = "SerialAdvanced::Open() Failed"; 00587 break; 00588 case serialErrSpeedInvalid: 00589 s = "SerialAdvanced::setSpeed() Invalid Speed Param"; 00590 break; 00591 case serialErrFlowInvalid: 00592 s = "SerialAdvanced::setFlow() Invalid Flow Param"; 00593 break; 00594 case serialErrParityInvalid: 00595 s = "SerialAdvanced::setParity() Invalid parity Param"; 00596 break; 00597 case serialErrCharsizeInvalid: 00598 s = "SerialAdvanced::setCharSize() Invalid Char Size"; 00599 break; 00600 case serialErrStopbitsInvalid: 00601 s = "SerialAdvanced::setStopBits() Invalid Stop Bits"; 00602 break; 00603 case serialErrOptionInvalid: 00604 break; 00605 case serialErrOutput: 00606 break; 00607 case serialErrReadFailed: 00608 s = "SerialAdvanced::read() Failed"; 00609 break; 00610 case serialErrReadTimedOut: 00611 s = "SerialAdvanced::read() Timed Out"; 00612 break; 00613 case serialErrWriteFailed: 00614 s = "SerialAdvanced::Write() Failed"; 00615 break; 00616 case serialErrFcntlFailed: 00617 s = "SerialAdvanced::Fcntl() Failed"; 00618 break; 00619 case serialErrTcGetAttrFailed: 00620 s = "SerialAdvanced::tcgetattr() Failed"; 00621 break; 00622 case serialErrTcSetAttrFailed: 00623 s = "SerialAdvanced::tcsetattr() Failed"; 00624 break; 00625 default: 00626 s = "Unknow error!"; 00627 } 00628 LERROR("%s", s); 00629 } 00630 00631 00632 // ###################################################################### 00633 SerialAdvanced::~SerialAdvanced(void) 00634 { } 00635 00636 00637 00638 // ###################################################################### 00639 /* So things look consistent in everyone's emacs... */ 00640 /* Local Variables: */ 00641 /* indent-tabs-mode: nil */ 00642 /* End: */