00001 /*!@file Devices/Serial.C 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: Nitin Dhavale <dhavale@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/Serial.C $ 00035 // $Id: Serial.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #include "Serial.H" 00039 #include <iostream> 00040 #include <sys/types.h> 00041 #include <dirent.h> 00042 #include <unistd.h> 00043 #include <string> 00044 #include <stdio.h> 00045 #include <string.h> 00046 00047 00048 //const ModelOptionDef OPT_DevName = 00049 //{ MODOPT_ARG(std::string), "DevName", &MOC_Serial, OPTEXP_CORE, 00050 // "Device file", 00051 // "serial-dev", '\0', "", "/dev/ttyUSB0" }; 00052 00053 // ###################################################################### 00054 00055 Serial::Serial() : 00056 itsCmdDevName("/dev/ttyUSB0"), 00057 itsDeviceDescription(""), 00058 itsSearchPrefix("ttyUSB"), 00059 itsBaud(9600), 00060 itsCharBits(8), 00061 itsStopBits(1), 00062 itsUseParity(false), 00063 itsParityOdd(false), 00064 itsFlowHard(false), 00065 itsFlowSoft(false), 00066 itsRdTout(0), 00067 itsBlocking(true), 00068 itsSerialOk(false), 00069 dev(-1), 00070 itsDevName(""), 00071 serialErrno(serialErrSuccess) 00072 { 00073 00074 } 00075 00076 // ###################################################################### 00077 void Serial::start() 00078 { 00079 //Check to see if we have a hardcoded device name. If so, then let's just 00080 //go ahead and enable that port. If 00081 printf("Looking Device Name [%s]\n",itsDevName.c_str()); 00082 if(itsDevName != "") 00083 { 00084 printf("Opening %s", itsDevName.c_str()); 00085 enablePort(itsDevName); 00086 } else if (itsDevName == "search") { 00087 printf("Searching for devices\n"); 00088 itsCmdDevName = ""; 00089 00090 DIR *directory_p; 00091 struct dirent *entry_p; 00092 00093 //Open the device directory to search for devices whose names match the search prefix 00094 directory_p = ::opendir ("/dev"); 00095 if (directory_p == NULL) 00096 printf("Could Not Open /dev Directory!\n"); 00097 00098 //Iterate through the directory entries 00099 while ((entry_p = ::readdir (directory_p))) 00100 { 00101 std::string entryName(entry_p->d_name); 00102 if(entryName.find(itsSearchPrefix.c_str()) != std::string::npos) 00103 {//If the directory entry name matches our search prefix, then let's try configuring a serial 00104 //port on that device, sending it an identity request command (0x00), and comparing the result 00105 //with our required device description 00106 00107 enablePort("/dev/" + entryName); 00108 unsigned char cmd[1] = {0}; 00109 00110 write(cmd,1); 00111 std::vector<unsigned char> deviceStringVec = readFrame(cmd[0], 255); 00112 00113 std::string deviceString(deviceStringVec.begin(), deviceStringVec.end()); 00114 printf("%s : %s", entryName.c_str(), deviceString.c_str()); 00115 00116 if(deviceString == itsDeviceDescription) 00117 { 00118 itsCmdDevName ="/dev/"+entryName; 00119 break; 00120 } 00121 } 00122 00123 00124 } 00125 (void) ::closedir (directory_p); 00126 if(itsCmdDevName == "") 00127 { 00128 printf("Could Not Find Serial Device Matching Descriptor (%s)\n", itsDeviceDescription.c_str()); 00129 } 00130 } else { 00131 printf("Opening from cmd line %s\n", itsCmdDevName.c_str()); 00132 enablePort(itsCmdDevName); 00133 } 00134 } 00135 00136 00137 // ###################################################################### 00138 void Serial::enablePort(std::string DeviceName) 00139 { 00140 closePort(); 00141 serialErrno = serialErrSuccess; // clear the error flag 00142 00143 openPort(DeviceName); // open the device 00144 perror(); 00145 00146 setSpeed(itsBaud); // Set the baud rate 00147 perror(); 00148 00149 setFlowControl(itsFlowHard, 00150 itsFlowSoft); // Set flow control 00151 perror(); 00152 00153 setCharBits(itsCharBits); // set no of bits in a char 00154 perror(); 00155 00156 setParity(itsUseParity, 00157 itsParityOdd); // Set even or odd parity 00158 perror(); 00159 00160 setBlocking(itsBlocking); // blocking mode? 00161 perror(); 00162 } 00163 00164 00165 #include <cstdio> 00166 // ###################################################################### 00167 void Serial::stop() 00168 { 00169 closePort(); 00170 } 00171 00172 // ###################################################################### 00173 void Serial::closePort() 00174 { 00175 if(dev >= 0) { 00176 //sendBreak(); 00177 close(dev); 00178 dev = -1; } 00179 } 00180 00181 // ###################################################################### 00182 void Serial::configureSearch(const std::string DeviceDescription, const int speed, const std::string SearchPrefix, const char *format, 00183 const bool flowSoft, const bool flowHard, 00184 const int tout) 00185 { 00186 printf("Search for %s in speed %d\n",DeviceDescription.c_str(),speed); 00187 itsDevName = "search"; 00188 itsDeviceDescription = DeviceDescription; 00189 itsSearchPrefix = SearchPrefix; 00190 //enable serch 00191 //configure("search", speed, format, flowSoft, flowHard, tout); 00192 //Bypass search 00193 configure("", speed, format, flowSoft, flowHard, tout); 00194 } 00195 00196 // ###################################################################### 00197 void Serial::configure(const char *dev, const int speed, const char *format, 00198 const bool flowSoft, const bool flowHard, 00199 const int tout) 00200 { 00201 itsDevName = dev; 00202 00203 00204 itsBaud = speed; 00205 itsFlowSoft = flowSoft; 00206 itsFlowHard = flowHard; 00207 itsRdTout = tout; 00208 00209 if (strlen(format) != 3) printf("Incorrect format string: %s", format); 00210 00211 switch(format[0]) { 00212 case '5': itsCharBits = 5; break; 00213 case '6': itsCharBits = 6; break; 00214 case '7': itsCharBits = 7; break; 00215 case '8': itsCharBits = 8; break; 00216 default: printf("Invalid charbits: %c (should be 5..8)", format[0]); 00217 } 00218 00219 switch(format[1]) { 00220 case 'N': itsUseParity = false; break; 00221 case 'E': itsUseParity = true; itsParityOdd = false; break; 00222 case 'O': itsUseParity = true; itsParityOdd = true; break; 00223 default: printf("Invalid parity: %c (should be N,E,O)", format[1]); 00224 } 00225 00226 switch(format[2]) { 00227 case '1': itsStopBits = (1); break; 00228 case '2': itsStopBits = (2); break; 00229 default: printf("Invalid stopbits: %c (should be 1..2)", format[2]); 00230 } 00231 } 00232 00233 // ###################################################################### 00234 serialError Serial::setSpeed(const int speed) 00235 { 00236 struct termios options; 00237 unsigned int rate; 00238 00239 switch(speed) 00240 { 00241 case 115200: 00242 rate = B115200; 00243 break; 00244 case 57600: 00245 rate = B57600; 00246 break; 00247 case 38400: 00248 rate = B38400; 00249 break; 00250 case 19200: 00251 rate = B19200; 00252 break; 00253 case 9600: 00254 rate = B9600; 00255 break; 00256 case 4800: 00257 rate = B4800; 00258 break; 00259 case 2400: 00260 rate = B2400; 00261 break; 00262 case 1200: 00263 rate = B1200; 00264 break; 00265 case 600: 00266 rate = B600; 00267 break; 00268 case 300: 00269 rate = B300; 00270 break; 00271 case 110: 00272 rate = B110; 00273 break; 00274 case 0: 00275 rate = B0; 00276 break; 00277 default: 00278 return serialError(serialErrSpeedInvalid); 00279 } 00280 00281 // get current options 00282 if(tcgetattr(dev, &options)==-1){ 00283 serialErrno = serialErrTcGetAttrFailed; 00284 return serialErrno; 00285 } 00286 00287 // set the speed 00288 cfsetispeed(&options, rate); 00289 cfsetospeed(&options, rate); 00290 00291 // change the terminals parameter instantly 00292 if( tcsetattr(dev, TCSANOW, &options) == -1){ 00293 serialErrno = serialErrTcSetAttrFailed; 00294 return serialErrno; 00295 } 00296 00297 if( tcgetattr(dev, &options) == -1) { 00298 serialErrno = serialErrTcGetAttrFailed; 00299 return serialErrno; 00300 } 00301 00302 // update our ModelParam: 00303 itsBaud=speed; 00304 00305 return serialErrSuccess; 00306 } 00307 00308 00309 // ###################################################################### 00310 serialError Serial::setFlowControl(const bool useHard, const bool useSoft) 00311 { 00312 termios options; 00313 00314 if( tcgetattr(dev, &options) == -1){ 00315 serialErrno = serialErrTcGetAttrFailed; 00316 return serialErrno; 00317 } 00318 00319 options.c_cflag &= ~CRTSCTS; 00320 options.c_iflag &= ~(IXON | IXANY | IXOFF); 00321 00322 if (useSoft) options.c_iflag |= (IXON | IXANY | IXOFF); 00323 if (useHard) options.c_cflag |= CRTSCTS; 00324 00325 if(tcsetattr(dev, TCSANOW, &options) == -1){ 00326 serialErrno = serialErrTcGetAttrFailed; 00327 return serialErrno; 00328 } 00329 00330 // update our ModelParams: 00331 itsFlowHard=useHard; 00332 itsFlowSoft=useSoft; 00333 00334 return serialErrSuccess; 00335 } 00336 00337 // ###################################################################### 00338 serialError Serial::setCharBits(const int bits) 00339 { 00340 termios options; 00341 00342 if(tcgetattr(dev, &options)==-1){ 00343 serialErrno = serialErrTcGetAttrFailed; 00344 return serialErrno; 00345 } 00346 00347 options.c_cflag &= ~CSIZE; // mask off the 'size' bits 00348 00349 switch(bits) 00350 { 00351 case 5: options.c_cflag |= CS5; break; 00352 case 6: options.c_cflag |= CS6; break; 00353 case 7: options.c_cflag |= CS7; break; 00354 case 8: options.c_cflag |= CS8; break; 00355 default: return serialError(serialErrCharsizeInvalid); 00356 } 00357 00358 if( tcsetattr(dev, TCSANOW, &options) == -1 ){ 00359 serialErrno = serialErrTcSetAttrFailed; 00360 return serialErrno; 00361 } 00362 00363 // update our ModelParam: 00364 itsCharBits=bits; 00365 00366 return serialErrSuccess; 00367 } 00368 00369 // ###################################################################### 00370 serialError Serial::setParity(const bool useParity, const bool oddParity) 00371 { 00372 struct termios options; 00373 00374 if(tcgetattr(dev, &options)==-1){ 00375 serialErrno = serialErrTcGetAttrFailed; 00376 return serialErrno; 00377 } 00378 00379 options.c_cflag &= ~(PARENB | PARODD); 00380 if (useParity) 00381 { 00382 if (oddParity) 00383 options.c_cflag |= (PARENB | PARODD); 00384 else 00385 options.c_cflag |= PARENB; 00386 } 00387 00388 if(tcsetattr(dev, TCSANOW, &options) == -1){ 00389 serialErrno = serialErrTcSetAttrFailed; 00390 return serialErrno; 00391 } 00392 00393 // update our ModelParams: 00394 itsUseParity=useParity; 00395 itsParityOdd=oddParity; 00396 00397 return serialErrSuccess; 00398 } 00399 00400 // ###################################################################### 00401 serialError Serial::setStopBits(const int bits) 00402 { 00403 struct termios options; 00404 00405 if(tcgetattr(dev, &options)==-1){ 00406 serialErrno = serialErrTcGetAttrFailed; 00407 return serialErrno; 00408 } 00409 00410 options.c_cflag &= ~CSTOPB; 00411 if (bits == 2) options.c_cflag |= CSTOPB; 00412 else if (bits != 1) return serialError(serialErrStopbitsInvalid); 00413 00414 if(tcsetattr(dev, TCSANOW, &options) == -1){ 00415 serialErrno = serialErrTcSetAttrFailed; 00416 return serialErrno; 00417 } 00418 00419 // update our ModelParam: 00420 itsStopBits=bits; 00421 00422 return serialErrSuccess; 00423 } 00424 00425 // ###################################################################### 00426 serialError Serial::setBlocking(const bool blocking) 00427 { 00428 int flags = fcntl(dev, F_GETFL, 0); 00429 if (flags == -1) printf("Cannot get flags"); 00430 if (blocking) flags &= (~O_NONBLOCK); else flags |= O_NONBLOCK; 00431 if (fcntl(dev, F_SETFL, flags) == -1) printf("Cannot set flags"); 00432 00433 itsBlocking=blocking; 00434 00435 return serialErrSuccess; 00436 } 00437 00438 // ###################################################################### 00439 void Serial::toggleDTR(const time_t ms) 00440 { 00441 struct termios tty, old; 00442 if(tcgetattr(dev, &tty) == -1 || tcgetattr(dev, &old) == -1){ 00443 serialErrno = serialErrTcGetAttrFailed; 00444 } 00445 00446 cfsetospeed(&tty, B0); 00447 cfsetispeed(&tty, B0); 00448 00449 if(tcsetattr(dev, TCSANOW, &tty) == -1){ 00450 serialErrno = serialErrTcSetAttrFailed; 00451 } 00452 00453 if(ms) 00454 usleep(ms*1000); 00455 00456 if(tcsetattr(dev, TCSANOW, &old) == -1){ 00457 serialErrno = serialErrTcSetAttrFailed; 00458 } 00459 } 00460 00461 // ###################################################################### 00462 void Serial::sendBreak(void) 00463 { 00464 // Send a Hangup to the port 00465 tcsendbreak(dev, 0); 00466 } 00467 00468 // ###################################################################### 00469 serialError Serial::error(const serialError serialErrorNum) 00470 { 00471 serialErrno = serialErrorNum; 00472 return serialErrorNum; 00473 } 00474 00475 // ###################################################################### 00476 int Serial::openPort(std::string DeviceName) 00477 { 00478 //const pid_t fuser = 00479 // rutz::unixcall::get_file_user_pid(DeviceName.c_str()); 00480 int fuser = 0; 00481 00482 if (fuser != 0 && DeviceName.compare("/dev/null") != 0) 00483 { 00484 printf("serial device %s is already in use by process pid=%d;\n" 00485 "\ttry using /dev/null or a different serial device instead", 00486 DeviceName.c_str(), int(fuser)); 00487 } 00488 00489 int flags= O_RDWR | O_NOCTTY; 00490 termios options; 00491 00492 // don't set the flag if we are setting a timeout on 00493 // the descriptor 00494 if (itsRdTout < 0) flags |= O_NDELAY; 00495 00496 printf("Opening port %s\n", DeviceName.c_str()); 00497 dev = ::open(DeviceName.c_str(), flags); 00498 if (dev == -1) { serialErrno = serialErrOpenFailed; return dev; } 00499 printf("Done\n"); 00500 00501 // Save current state 00502 if( tcgetattr(dev, &savedState) == -1 ){ 00503 serialErrno = serialErrTcGetAttrFailed; 00504 return -1; 00505 } 00506 00507 // reset all the flags 00508 if( fcntl(dev, F_SETFL, 0) == -1 ){ 00509 serialErrno = serialErrFcntlFailed; 00510 return -1; 00511 } 00512 00513 if(tcgetattr(dev, &options) == -1 ){ 00514 serialErrno = serialErrTcGetAttrFailed; 00515 return -1; 00516 } 00517 00518 // get raw input from the port 00519 options.c_cflag |= ( CLOCAL // ignore modem control lines 00520 | CREAD ); // enable the receiver 00521 00522 options.c_iflag &= ~( IGNBRK // ignore BREAK condition on input 00523 | BRKINT // If IGNBRK is not set, generate SIGINT 00524 // on BREAK condition, else read BREAK as \0 00525 | PARMRK 00526 | ISTRIP // strip off eighth bit 00527 | INLCR // donot translate NL to CR on input 00528 | IGNCR // ignore CR 00529 | ICRNL // translate CR to newline on input 00530 | IXON // disable XON/XOFF flow control on output 00531 ); 00532 00533 // disable implementation-defined output processing 00534 options.c_oflag &= ~OPOST; 00535 options.c_lflag &= ~(ECHO // dont echo i/p chars 00536 | ECHONL // do not echo NL under any circumstance 00537 | ICANON // disable cannonical mode 00538 | ISIG // do not signal for INTR, QUIT, SUSP etc 00539 | IEXTEN // disable platform dependent i/p processing 00540 ); 00541 00542 // set a timeout on the descriptor 00543 if(itsRdTout > 0) { 00544 options.c_cc[VMIN] = 0; 00545 options.c_cc[VTIME] = itsRdTout; 00546 } 00547 00548 if( tcsetattr(dev, TCSANOW, &options) == -1){ 00549 serialErrno = serialErrTcSetAttrFailed; 00550 return -1; 00551 } 00552 return dev; 00553 } 00554 00555 00556 // ###################################################################### 00557 int Serial::read(void* buffer, const int nbytes) 00558 { 00559 int n = ::read(dev, buffer, nbytes); 00560 if(n==-1) 00561 serialErrno = serialErrReadFailed; 00562 00563 if(n==0) 00564 serialErrno = serialErrReadTimedOut; 00565 00566 return n; 00567 } 00568 00569 00570 // ###################################################################### 00571 char Serial::read(void) 00572 { 00573 char ch; 00574 00575 this->read(&ch, 1); 00576 00577 return ch; 00578 } 00579 00580 std::vector<unsigned char> Serial::readFrame(const unsigned char frameStart, const unsigned char frameEnd, const int frameLength, const double timeout) 00581 { 00582 00583 std::vector<unsigned char> data; 00584 unsigned char buffer[1024]; 00585 00586 00587 //Read data into the data buffer 00588 //printf("Reading buffer..."); 00589 int bytesRead = read(buffer, 1024); 00590 //printf("bytesRead[%d]\n",bytesRead); 00591 if(bytesRead > 0) 00592 { 00593 // printf("buffer0[%d],framestart[%d]",buffer[0],frameStart); 00594 if(frameStart!=buffer[0]) 00595 return std::vector<unsigned char>(); 00596 int framesize = buffer[1]; 00597 // printf("framesize[%d]\n",framesize); 00598 for(int i=0;i<framesize;i++) 00599 data.push_back(buffer[i+2]); 00600 return data; 00601 00602 } 00603 else 00604 { //If the serial read returned 0 bytes, then just wait for a bit before reading again 00605 usleep(1000); 00606 printf("Read Fail\n"); 00607 00608 //If the timer has expired, then let's just return an empty vector 00609 //if(/*timer.getSecs() > timeout && */timeout > 0) 00610 return std::vector<unsigned char>(); 00611 } 00612 } 00613 00614 00615 // ###################################################################### 00616 int Serial::write(const void* buffer, const int nbytes) 00617 { 00618 //char c[3] = { 0xff, 0x01, 0xff }; 00619 //::write(dev, c, 3); 00620 00621 int n = ::write(dev, buffer, nbytes); 00622 00623 /* 00624 //printf("----------------- WRITE --------------------"); 00625 for(int i=0; i<n; ++i) 00626 { 00627 fprintf(stderr, "%02X ", 00628 (static_cast<const unsigned char*>(buffer)[i])&0xff); 00629 } 00630 fprintf(stderr,"\n"); 00631 //printf("-------------------------------------------"); 00632 */ 00633 00634 if(n==-1) 00635 serialErrno = serialErrWriteFailed; 00636 00637 return n; 00638 } 00639 00640 // ###################################################################### 00641 int Serial::write(const unsigned char character) 00642 { 00643 return write(&character, 1); 00644 } 00645 00646 00647 // ###################################################################### 00648 void Serial::flush(void) 00649 { 00650 //Flush the input 00651 int status = tcflush(dev,TCIFLUSH); 00652 if(status != 0) 00653 printf("BAD SERIAL FLUSH"); 00654 00655 } 00656 00657 // ###################################################################### 00658 void Serial::perror(void) 00659 { 00660 switch(serialErrno) 00661 { 00662 case serialErrSuccess: 00663 printf("Serial::OK\n"); 00664 return; 00665 case serialErrOpenNoTty: 00666 printf("Serial::Open() No TTY Failed"); 00667 break; 00668 case serialErrOpenFailed: 00669 printf("Serial::Open() Failed"); 00670 break; 00671 case serialErrSpeedInvalid: 00672 printf("Serial::setSpeed() Invalid Speed Param"); 00673 break; 00674 case serialErrFlowInvalid: 00675 printf("Serial::setFlow() Invalid Flow Param"); 00676 break; 00677 case serialErrParityInvalid: 00678 printf("Serial::setParity() Invalid parity Param"); 00679 break; 00680 case serialErrCharsizeInvalid: 00681 printf("Serial::setCharSize() Invalid Char Size"); 00682 break; 00683 case serialErrStopbitsInvalid: 00684 printf("Serial::setStopBits() Invalid Stop Bits"); 00685 break; 00686 case serialErrOptionInvalid: 00687 printf("Serial::read() invalid option"); 00688 break; 00689 case serialErrOutput: 00690 printf("Serial::read() err output"); 00691 break; 00692 case serialErrReadFailed: 00693 printf("Serial::read() Failed"); 00694 break; 00695 case serialErrReadTimedOut: 00696 printf("Serial::read() Timed Out"); 00697 break; 00698 case serialErrWriteFailed: 00699 printf("Serial::Write() Failed"); 00700 break; 00701 case serialErrFcntlFailed: 00702 printf("Serial::Fcntl() Failed"); 00703 break; 00704 case serialErrTcGetAttrFailed: 00705 printf("Serial::tcgetattr() Failed"); 00706 break; 00707 case serialErrTcSetAttrFailed: 00708 printf("Serial::tcsetattr() Failed"); 00709 break; 00710 default: 00711 printf("Unknow error!"); 00712 } 00713 } 00714 00715 00716 // ###################################################################### 00717 Serial::~Serial(void) 00718 { } 00719 00720 00721 00722 // ###################################################################### 00723 /* So things look consistent in everyone's emacs... */ 00724 /* Local Variables: */ 00725 /* indent-tabs-mode: nil */ 00726 /* End: */