00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00043
00044
00045
00046 LOW_portSerial_Linux::LOW_portSerial_Linux( const LOW_portSerialFactory::portSpecifier_t inSerialPort) :
00047 serialPortPath( inSerialPort)
00048 {
00049
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
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
00080 if( tcgetattr( serialFD, &term) < 0 )
00081 throw portSerial_error( errno, "Error with tcgetattr", __FILE__, __LINE__);
00082
00083
00084 term.c_iflag = IGNBRK;
00085 term.c_oflag = 0;
00086 term.c_cflag = CREAD | HUPCL;
00087 term.c_lflag = 0;
00088
00089
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;
00201 }
00202 else {
00203 serial.flags = (serial.flags & ~ASYNC_SPD_MASK);
00204 }
00205
00206
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
00256 wait_tm.tv_usec = 0;
00257 wait_tm.tv_sec = inSecTimeout;
00258 FD_ZERO( &readset);
00259 FD_SET( serialFD, &readset);
00260
00261
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
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