SerialAdvanced.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:40:38 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3