Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

LOW_portSerial_Linux.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           LOW_portSerialLinux.cpp  -  description
00003                              -------------------
00004     begin                : Mon Jul 29 2002
00005     copyright            : (C) 2002 by Harald Roelle, Helmut Reiser
00006     email                : roelle@informatik.uni-muenchen.de, reiser@informatik.uni-muenchen.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018  
00019 #include <stdio.h>
00020 #include <errno.h>
00021 #include <unistd.h>
00022 #include <fcntl.h>
00023 #include <linux/serial.h>
00024 #include <termios.h>
00025 #include <sys/stat.h>
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 #include <sys/time.h>
00029 #include <sys/ioctl.h>
00030 
00031 
00032 #include "LOW_portSerial_Linux.h"
00033 #include "LOW_helper_msglog.h"
00034 
00035 
00036 
00037 //=====================================================================================
00038 //
00039 // constructors
00040 //
00041 
00042 
00043 LOW_portSerial_Linux::LOW_portSerial_Linux( const string inSerialPort) :
00044   serialPortPath( inSerialPort)
00045 {
00046   // Open the serial port, turning on devices
00047   if ( (serialFD=open( serialPortPath.c_str(), O_RDWR)) == -1 ) {
00048     throw portSerial_error( errno, "Error opening tty " + serialPortPath, __FILE__, __LINE__);
00049   }
00050 }
00051   
00052 
00053 LOW_portSerial_Linux::~LOW_portSerial_Linux()
00054 {
00055   close( serialFD);
00056 }
00057 
00058 
00059 
00060 //=====================================================================================
00061 //
00062 // methods
00063 //
00064 
00065 void LOW_portSerial_Linux::tty_configure( const flowControl_t inFlowCtl, const dataBitsSite_t inDataBits,
00066                                           const parity_t inParity, const stopBits_t inStopBits, const speed_t inSpeed) const
00067 {
00068   struct serial_struct   serial;
00069   struct termios         term;
00070   
00071   
00072   if ( ioctl( serialFD, TIOCGSERIAL, &serial) < 0 )
00073     throw portSerial_error( errno, "TIOCGSERIAL failed", __FILE__, __LINE__);
00074     
00075   // Get the current device settings
00076   if( tcgetattr( serialFD, &term) < 0 )
00077     throw portSerial_error( errno, "Error with tcgetattr", __FILE__, __LINE__);
00078 
00079   // preset settings
00080   term.c_iflag = IGNBRK;
00081   term.c_oflag = 0;
00082   term.c_cflag = CREAD | HUPCL;
00083   term.c_lflag = 0;
00084 
00085   // set the config values
00086             
00087   switch ( inFlowCtl ) {
00088     
00089     case none_flowControl:
00090       term.c_cflag |= CLOCAL;
00091       break;
00092     
00093     case xonxoff_flowControl:
00094       term.c_iflag |= IXON | IXOFF;
00095       term.c_cflag |= CLOCAL;
00096       break;
00097     
00098     case rtscts_flowControl:
00099       term.c_cflag |= CRTSCTS;
00100       break;
00101       
00102     default:
00103       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00104       break;
00105   }
00106   
00107   switch ( inParity ) {
00108     
00109     case no_parity:
00110       term.c_iflag |= IGNPAR;
00111       break;
00112     
00113     case odd_parity:
00114       term.c_iflag |= INPCK;
00115       term.c_cflag |= PARENB | PARODD;
00116       break;
00117     
00118     case even_parity:
00119       term.c_iflag |= INPCK;
00120       term.c_cflag |= PARENB;
00121       break;
00122       
00123     default:
00124       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00125       break;
00126   }
00127   
00128   switch ( inDataBits ) {
00129     
00130     case bit5_size:
00131       term.c_cflag |= CS5;
00132       break;
00133   
00134     case bit6_size:
00135       term.c_cflag |= CS6;
00136       break;
00137   
00138     case bit7_size:
00139       term.c_cflag |= CS7;
00140       break;
00141   
00142     case bit8_size:
00143       term.c_cflag |= CS8;
00144       break;
00145       
00146     default:
00147       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00148       break;
00149   }
00150   
00151   switch ( inStopBits ) {
00152     
00153     case bit1_stopBit:
00154       break;
00155   
00156     case bit2_stopBit:
00157       term.c_cflag |= CSTOPB;
00158       break;
00159       
00160     default:
00161       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00162       break;
00163   }
00164   
00165   int speed = 0;
00166   switch ( inSpeed ) {
00167     case B50_speed:     speed = B50;      break;
00168     case B75_speed:     speed = B75;      break;
00169     case B110_speed:    speed = B110;     break;
00170     case B134_speed:    speed = B134;     break;
00171     case B150_speed:    speed = B150;     break;
00172     case B200_speed:    speed = B200;     break;
00173     case B300_speed:    speed = B300;     break;
00174     case B600_speed:    speed = B600;     break;
00175     case B1200_speed:   speed = B1200;    break;
00176     case B1800_speed:   speed = B1800;    break;
00177     case B2400_speed:   speed = B2400;    break;
00178     case B4800_speed:   speed = B4800;    break;
00179     case B9600_speed:   speed = B9600;    break;
00180     case B19200_speed:  speed = B19200;   break;
00181     case B38400_speed:  speed = B38400;   break;
00182     case B57600_speed:  speed = B57600;   break;
00183     case B115200_speed: speed = B115200;  break;
00184     
00185     case B10472_speed:  speed = B38400;   break;
00186     
00187     default:
00188       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00189       break;
00190   }
00191   cfsetospeed( &term, speed);
00192   cfsetispeed( &term, speed);
00193   
00194   if ( inSpeed == B10472_speed ) {
00195     serial.flags = (serial.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
00196     serial.custom_divisor = 11;   // 10472bps
00197   }
00198   else {
00199     serial.flags = (serial.flags & ~ASYNC_SPD_MASK);  // make 38400 really 38400
00200   }
00201   
00202   // read one byte without timeout. timeouts will be done by select
00203   term.c_cc[VMIN]  = 1;
00204   term.c_cc[VTIME] = 0;
00205     
00206   if ( ioctl( serialFD, TIOCSSERIAL, &serial) < 0 )
00207     throw portSerial_error( errno, "TIOCSSERIAL failed", __FILE__, __LINE__);
00208   
00209   if( tcsetattr( serialFD, TCSAFLUSH, &term ) < 0 )
00210     throw portSerial_error( errno, "Error with tcsetattr", __FILE__, __LINE__);
00211 }
00212 
00213 
00214 //void LOW_portSerial_Linux::tty_confPasvNormal() const
00215 //{
00216 //  struct serial_struct   serial;
00217 //  struct termios         term;
00218 //  
00219 //  if( ioctl( serialFD, TIOCGSERIAL, &serial) < 0 )
00220 //    throw portSerial_error( errno, "TIOCGSERIAL failed", __FILE__, __LINE__);
00221 //
00222 //  // Get the current device settings
00223 //  if( tcgetattr( serialFD, &term) < 0 )
00224 //    throw portSerial_error( errno, "Error with tcgetattr", __FILE__, __LINE__);
00225 //  
00226 //  serial.flags = (serial.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
00227 //  serial.custom_divisor = 1; // 115200bps
00228 //  
00229 //  ioctl( serialFD, TIOCSSERIAL, &serial );
00230 //  
00231 //  term.c_lflag = 0;
00232 //  term.c_iflag = 0;
00233 //  term.c_oflag = 0;
00234 //
00235 //  // 1 byte at a time, no timer
00236 //  term.c_cc[VMIN]  = 1;
00237 //  term.c_cc[VTIME] = 0;
00238 //
00239 //  term.c_cflag = CS6 | CREAD | HUPCL | CLOCAL | B38400;
00240 //
00241 //  cfsetispeed( &term, B115200 ); // Set input speed to 115.2k
00242 //  cfsetospeed( &term, B115200 ); // Set output speed to 115.2k
00243 //
00244 //  if( tcsetattr( serialFD, TCSANOW, &term ) < 0 )
00245 //    throw portSerial_error( errno, "Error with tcsetattr", __FILE__, __LINE__);
00246 //}
00247 
00248 
00249 //void LOW_portSerial_Linux::tty_confPasvReset() const
00250 //{
00251 //  struct serial_struct   serial;
00252 //  struct termios         term;
00253 //  
00254 //  if( ioctl( serialFD, TIOCGSERIAL, &serial) < 0 )
00255 //    throw portSerial_error( errno, "TIOCGSERIAL failed", __FILE__, __LINE__);
00256 //
00257 //  // Get the current device settings
00258 //  if( tcgetattr( serialFD, &term) < 0 )
00259 //    throw portSerial_error( errno, "Error with tcgetattr", __FILE__, __LINE__);
00260 //  
00261 //  serial.flags = (serial.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
00262 //  serial.custom_divisor = 11;   // 10472bps
00263 //  
00264 //  ioctl( serialFD, TIOCSSERIAL, &serial );
00265 //  
00266 //  term.c_lflag = 0;
00267 //  term.c_iflag = 0;
00268 //  term.c_oflag = 0;
00269 //
00270 //  // 1 byte at a time, no timer
00271 //  term.c_cc[VMIN]  = 1;
00272 //  term.c_cc[VTIME] = 0;
00273 //
00274 //  term.c_cflag = CS8 | CREAD | HUPCL | CLOCAL | B38400;
00275 //
00276 //  if( tcsetattr( serialFD, TCSANOW, &term ) < 0 )
00277 //    throw portSerial_error( errno, "Error with tcsetattr", __FILE__, __LINE__);
00278 //  
00279 //}
00280 
00281 
00282 void LOW_portSerial_Linux::tty_flush( const bool inFlushIn, const bool inFlushOut) const
00283 {
00284   if      (  inFlushIn && !inFlushOut ) {
00285     tcflush( serialFD, TCIFLUSH);
00286   }
00287   else if ( !inFlushIn &&  inFlushOut ) {
00288     tcflush( serialFD, TCOFLUSH);
00289   }
00290   else if (  inFlushIn &&  inFlushOut ) {
00291     tcflush( serialFD, TCIOFLUSH);
00292   }
00293 }
00294 
00295 
00296 void LOW_portSerial_Linux::tty_break() const
00297 {
00298   tcsendbreak( serialFD, 20);
00299 }
00300 
00301   
00302 uint8_t LOW_portSerial_Linux::tty_readByte( const bool inTrashExtraReply) const
00303 {
00304   fd_set         readset;
00305   struct timeval wait_tm;
00306   int            selRet;
00307   uint8_t        retVal = 0;
00308 
00309   for( int a=0; a<((inTrashExtraReply==true)?2:1); a++) {
00310     
00311     while ( true ) {
00312       
00313       // Setup for wait for a response or timeout
00314       wait_tm.tv_usec = 0;
00315       wait_tm.tv_sec  = serialTimeout;
00316       FD_ZERO( &readset);
00317       FD_SET( serialFD, &readset);
00318         
00319       // Read byte if it doesn't timeout first
00320       selRet = select( serialFD+1, &readset, NULL, NULL, &wait_tm);
00321       if( selRet > 0 ) {
00322         
00323         if( FD_ISSET( serialFD, &readset) ) 
00324         {
00325           uint8_t readByte;
00326   
00327           if ( read( serialFD, &readByte, 1) != 1 )
00328             throw portSerial_error( "Unexpected short read", __FILE__, __LINE__);
00329           
00330           if ( a == 0 )
00331             retVal = readByte;
00332       
00333           LOW_helper_msglog::printDebug( LOW_helper_msglog::portSerial_dl, "LOW_linkDS2480B: TTY READ: %02x read cycle: %d\n", readByte, a);
00334           
00335           break;
00336         }
00337        
00338       }
00339       else if ( selRet == 0 ) {
00340         throw portSerial_error( "TTY operation timed out", __FILE__, __LINE__);
00341       }
00342       else {
00343         throw portSerial_error( errno, "Unexpected error in select call", __FILE__, __LINE__);
00344       }
00345     
00346     }
00347   }
00348   
00349   return retVal;
00350 }
00351 
00352 
00353 void LOW_portSerial_Linux::tty_read( byteVec_t &outReadBytes, const bool inTrashExtraReply) const
00354 {
00355   for( unsigned int a=0; a<outReadBytes.size(); a++) {
00356     outReadBytes[a] = tty_readByte( inTrashExtraReply);
00357   }
00358 }
00359 
00360 
00361 void LOW_portSerial_Linux::tty_write( const uint8_t inWriteByte) const
00362 {
00363   int written;
00364   
00365   LOW_helper_msglog::printDebug( LOW_helper_msglog::portSerial_dl, "LOW_linkDS2480B: TTY WRITE: %02x\n", inWriteByte);
00366   do {
00367     written = write( serialFD, &inWriteByte, 1);
00368     if ( written == -1 )
00369       throw portSerial_error( errno, "Error writing single byte to TTY", __FILE__, __LINE__);
00370     tcdrain( serialFD);
00371   }
00372   while ( written != 1 );
00373 }
00374 
00375 
00376 void LOW_portSerial_Linux::tty_write( const byteVec_t &inWriteBytes) const
00377 {
00378   unsigned int  total   = inWriteBytes.size();
00379   uint8_t       *buffer = (uint8_t*)malloc( total);;
00380     
00381   try {
00382     //this is a bit stupid, but I'm so stupid that I don't know how to make it better
00383     for( unsigned int a=0; a<total; a++) {
00384       buffer[a] = inWriteBytes[a];
00385       LOW_helper_msglog::printDebug( LOW_helper_msglog::portSerial_dl, "LOW_linkDS2480B: TTY WRITE: %02x\n", buffer[a]);
00386     }
00387     
00388     int           written   = 0;
00389     unsigned int  remaining = total;
00390     uint8_t       *writePtr = buffer;
00391     do {
00392       // I had troubles with writing to fast, so block the stuff a bit
00393       written = write( serialFD, writePtr, (remaining<4)?remaining:4);
00394       if ( written == -1 )
00395         throw portSerial_error( errno, "Error writing byte block to TTY", __FILE__, __LINE__);
00396       tcdrain( serialFD);
00397       remaining -= written;
00398       writePtr  += written;
00399     }
00400     while ( remaining != 0);
00401   }
00402   catch( ... ) {
00403     free( buffer);
00404     throw;
00405   }
00406   
00407   free( buffer);
00408 }
00409 

Generated on Sun Jan 12 21:07:43 2003 by doxygen1.2.13.1 written by Dimitri van Heesch, © 1997-2001