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
00006     email                : roelle@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 #include <memory>
00032 #include <new>
00033 
00034 
00035 #include "LOW_portSerial_Linux.h"
00036 #include "LOW_helper_msglog.h"
00037 
00038 
00039 
00040 //=====================================================================================
00041 //
00042 // constructors
00043 //
00044 
00045 
00046 LOW_portSerial_Linux::LOW_portSerial_Linux( const LOW_portSerialFactory::portSpecifier_t inSerialPort) :
00047   serialPortPath( inSerialPort)
00048 {
00049   // Open the serial port, turning on devices
00050   if ( (serialFD=open( serialPortPath.c_str(), O_RDWR)) == -1 ) {
00051     throw portSerial_error( errno, "Error opening tty " + serialPortPath, __FILE__, __LINE__);
00052   }
00053 }
00054   
00055 
00056 LOW_portSerial_Linux::~LOW_portSerial_Linux()
00057 {
00058   close( serialFD);
00059 }
00060 
00061 
00062 
00063 //=====================================================================================
00064 //
00065 // methods
00066 //
00067 
00068 void LOW_portSerial_Linux::tty_configure( const flowControl_t inFlowCtl, const dataBitsSite_t inDataBits,
00069                                           const parity_t inParity, const stopBits_t inStopBits, const speed_t inSpeed)
00070 {
00071   __LOW_SYNCHRONIZE_METHOD_WRITE__
00072 
00073   struct serial_struct   serial;
00074   struct termios         term;
00075   
00076   if ( ioctl( serialFD, TIOCGSERIAL, &serial) < 0 )
00077     throw portSerial_error( errno, "TIOCGSERIAL failed", __FILE__, __LINE__);
00078     
00079   // Get the current device settings
00080   if( tcgetattr( serialFD, &term) < 0 )
00081     throw portSerial_error( errno, "Error with tcgetattr", __FILE__, __LINE__);
00082 
00083   // preset settings
00084   term.c_iflag = IGNBRK;
00085   term.c_oflag = 0;
00086   term.c_cflag = CREAD | HUPCL;
00087   term.c_lflag = 0;
00088 
00089   // set the config values
00090             
00091   switch ( inFlowCtl ) {
00092     
00093     case none_flowControl:
00094       term.c_cflag |= CLOCAL;
00095       break;
00096     
00097     case xonxoff_flowControl:
00098       term.c_iflag |= IXON | IXOFF;
00099       term.c_cflag |= CLOCAL;
00100       break;
00101     
00102     case rtscts_flowControl:
00103       term.c_cflag |= CRTSCTS;
00104       break;
00105       
00106     default:
00107       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00108       break;
00109   }
00110   
00111   switch ( inParity ) {
00112     
00113     case no_parity:
00114       term.c_iflag |= IGNPAR;
00115       break;
00116     
00117     case odd_parity:
00118       term.c_iflag |= INPCK;
00119       term.c_cflag |= PARENB | PARODD;
00120       break;
00121     
00122     case even_parity:
00123       term.c_iflag |= INPCK;
00124       term.c_cflag |= PARENB;
00125       break;
00126       
00127     default:
00128       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00129       break;
00130   }
00131   
00132   switch ( inDataBits ) {
00133     
00134     case bit5_size:
00135       term.c_cflag |= CS5;
00136       break;
00137   
00138     case bit6_size:
00139       term.c_cflag |= CS6;
00140       break;
00141   
00142     case bit7_size:
00143       term.c_cflag |= CS7;
00144       break;
00145   
00146     case bit8_size:
00147       term.c_cflag |= CS8;
00148       break;
00149       
00150     default:
00151       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00152       break;
00153   }
00154   
00155   switch ( inStopBits ) {
00156     
00157     case bit1_stopBit:
00158       break;
00159   
00160     case bit2_stopBit:
00161       term.c_cflag |= CSTOPB;
00162       break;
00163       
00164     default:
00165       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00166       break;
00167   }
00168   
00169   int speed = 0;
00170   switch ( inSpeed ) {
00171     case B50_speed:     speed = B50;      break;
00172     case B75_speed:     speed = B75;      break;
00173     case B110_speed:    speed = B110;     break;
00174     case B134_speed:    speed = B134;     break;
00175     case B150_speed:    speed = B150;     break;
00176     case B200_speed:    speed = B200;     break;
00177     case B300_speed:    speed = B300;     break;
00178     case B600_speed:    speed = B600;     break;
00179     case B1200_speed:   speed = B1200;    break;
00180     case B1800_speed:   speed = B1800;    break;
00181     case B2400_speed:   speed = B2400;    break;
00182     case B4800_speed:   speed = B4800;    break;
00183     case B9600_speed:   speed = B9600;    break;
00184     case B19200_speed:  speed = B19200;   break;
00185     case B38400_speed:  speed = B38400;   break;
00186     case B57600_speed:  speed = B57600;   break;
00187     case B115200_speed: speed = B115200;  break;
00188     
00189     case B10472_speed:  speed = B38400;   break;
00190     
00191     default:
00192       throw portSerial_error( "Unknown control parameter value", __FILE__, __LINE__);
00193       break;
00194   }
00195   cfsetospeed( &term, speed);
00196   cfsetispeed( &term, speed);
00197   
00198   if ( inSpeed == B10472_speed ) {
00199     serial.flags = (serial.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
00200     serial.custom_divisor = 11;   // 10472bps
00201   }
00202   else {
00203     serial.flags = (serial.flags & ~ASYNC_SPD_MASK);  // make 38400 really 38400
00204   }
00205   
00206   // read one byte without timeout. timeouts will be done by select
00207   term.c_cc[VMIN]  = 1;
00208   term.c_cc[VTIME] = 0;
00209     
00210   if ( ioctl( serialFD, TIOCSSERIAL, &serial) < 0 )
00211     throw portSerial_error( errno, "TIOCSSERIAL failed", __FILE__, __LINE__);
00212   
00213   if( tcsetattr( serialFD, TCSAFLUSH, &term ) < 0 )
00214     throw portSerial_error( errno, "Error with tcsetattr", __FILE__, __LINE__);
00215 }
00216 
00217 
00218 void LOW_portSerial_Linux::tty_flush( const bool inFlushIn, const bool inFlushOut)
00219 {
00220   __LOW_SYNCHRONIZE_METHOD_WRITE__
00221 
00222   if      (  inFlushIn && !inFlushOut ) {
00223     tcflush( serialFD, TCIFLUSH);
00224   }
00225   else if ( !inFlushIn &&  inFlushOut ) {
00226     tcflush( serialFD, TCOFLUSH);
00227   }
00228   else if (  inFlushIn &&  inFlushOut ) {
00229     tcflush( serialFD, TCIOFLUSH);
00230   }
00231 }
00232 
00233 
00234 void LOW_portSerial_Linux::tty_break()
00235 {
00236   __LOW_SYNCHRONIZE_METHOD_WRITE__
00237 
00238   tcsendbreak( serialFD, 20);
00239 }
00240 
00241   
00242 uint8_t LOW_portSerial_Linux::tty_readByte( const bool inTrashExtraReply, const unsigned int inSecTimeout)
00243 {
00244   __LOW_SYNCHRONIZE_METHOD_WRITE_WEAK__
00245 
00246   fd_set         readset;
00247   struct timeval wait_tm;
00248   int            selRet;
00249   uint8_t        retVal = 0;
00250 
00251   for( int a=0; a<((inTrashExtraReply==true)?2:1); a++) {
00252     
00253     while ( true ) {
00254       
00255       // Setup for wait for a response or timeout
00256       wait_tm.tv_usec = 0;
00257       wait_tm.tv_sec  = inSecTimeout;
00258       FD_ZERO( &readset);
00259       FD_SET( serialFD, &readset);
00260         
00261       // Read byte if it doesn't timeout first
00262       selRet = select( serialFD+1, &readset, NULL, NULL, &wait_tm);
00263       if( selRet > 0 ) {
00264         
00265         if( FD_ISSET( serialFD, &readset) ) 
00266         {
00267           uint8_t readByte;
00268   
00269           if ( read( serialFD, &readByte, 1) != 1 )
00270             throw portSerial_error( "Unexpected short read", __FILE__, __LINE__);
00271           
00272           if ( a == 0 )
00273             retVal = readByte;
00274       
00275           LOW_helper_msglog::printDebug( LOW_helper_msglog::portSerial_dl, "LOW_linkDS2480B: TTY READ: %02x read cycle: %d\n", readByte, a);
00276           
00277           break;
00278         }
00279        
00280       }
00281       else if ( selRet == 0 ) {
00282         throw portSerial_error( "TTY operation timed out", __FILE__, __LINE__);
00283       }
00284       else {
00285         throw portSerial_error( errno, "Unexpected error in select call", __FILE__, __LINE__);
00286       }
00287     
00288     }
00289   }
00290   
00291   return retVal;
00292 }
00293 
00294 
00295 void LOW_portSerial_Linux::tty_read( byteVec_t &outReadBytes, const bool inTrashExtraReply, const unsigned int inSecTimeout)
00296 {
00297   __LOW_SYNCHRONIZE_METHOD_WRITE__
00298 
00299   for( unsigned int a=0; a<outReadBytes.size(); a++) {
00300     outReadBytes[a] = tty_readByte( inTrashExtraReply, inSecTimeout);
00301   }
00302 }
00303 
00304 
00305 void LOW_portSerial_Linux::tty_write( const uint8_t inWriteByte)
00306 {
00307   __LOW_SYNCHRONIZE_METHOD_WRITE__
00308 
00309   int written;
00310   
00311   LOW_helper_msglog::printDebug( LOW_helper_msglog::portSerial_dl, "LOW_linkDS2480B: TTY WRITE: %02x\n", inWriteByte);
00312   do {
00313     written = write( serialFD, &inWriteByte, 1);
00314     if ( written == -1 )
00315       throw portSerial_error( errno, "Error writing single byte to TTY", __FILE__, __LINE__);
00316     tcdrain( serialFD);
00317   }
00318   while ( written != 1 );
00319 }
00320 
00321 
00322 void LOW_portSerial_Linux::tty_write( const byteVec_t &inWriteBytes)
00323 {
00324   __LOW_SYNCHRONIZE_METHOD_WRITE__
00325 
00326   unsigned int  total   = inWriteBytes.size();
00327   uint8_t       *buffer = new uint8_t[total];
00328     
00329   try {
00330     std::copy( inWriteBytes.begin(), inWriteBytes.end(), buffer);
00331     
00332     int           written   = 0;
00333     unsigned int  remaining = total;
00334     uint8_t       *writePtr = buffer;
00335     do {
00336       // I had troubles with writing to fast, so block the stuff a bit
00337       written = write( serialFD, writePtr, (remaining<4)?remaining:4);
00338       if ( written == -1 )
00339         throw portSerial_error( errno, "Error writing byte block to TTY", __FILE__, __LINE__);
00340       tcdrain( serialFD);
00341       remaining -= written;
00342       writePtr  += written;
00343     }
00344     while ( remaining != 0);
00345   }
00346   catch( ... ) {
00347     delete[] buffer;
00348     throw;
00349   }
00350   
00351   delete[] buffer;
00352 }
00353 

Generated on Tue Feb 3 11:30:26 2004 for OneWireLibrary++ by doxygen 1.3.2