serial.cxx

00001 // serial.cxx -- Unix serial I/O support
00002 //
00003 // Written by Curtis Olson, started November 1998.
00004 //
00005 // Copyright (C) 1998  Curtis L. Olson - http://www.flightgear.org/~curt
00006 //
00007 // This library is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU Library General Public
00009 // License as published by the Free Software Foundation; either
00010 // version 2 of the License, or (at your option) any later version.
00011 //
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 // Library General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with this program; if not, write to the Free Software
00019 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020 //
00021 // $Id: serial_8cxx-source.html,v 1.15 2007-12-17 15:37:10 curt Exp $
00022 
00023 
00024 #include <simgear/compiler.h>
00025 
00026 #include STL_IOSTREAM
00027 
00028 #ifdef SG_HAVE_STD_INCLUDE
00029 #  include <cerrno>
00030 #else
00031 #  include <errno.h>
00032 #endif
00033 
00034 #if !defined( WIN32 ) || defined( __CYGWIN__) || defined( __CYGWIN32__ )
00035 #  include <termios.h>
00036 #  include <sys/types.h>
00037 #  include <sys/stat.h>
00038 #  include <fcntl.h>
00039 #  include <unistd.h>
00040 #endif
00041 
00042 #include <simgear/debug/logstream.hxx>
00043 
00044 #include "serial.hxx"
00045 
00046 SGSerialPort::SGSerialPort()
00047     : dev_open(false)
00048 {
00049     // empty
00050 }
00051 
00052 SGSerialPort::SGSerialPort(const string& device, int baud) {
00053     open_port(device);
00054     
00055     if ( dev_open ) {
00056         set_baud(baud);
00057     }
00058 }
00059 
00060 SGSerialPort::~SGSerialPort() {
00061     // closing the port here screws us up because if we would even so
00062     // much as make a copy of an SGSerialPort object and then delete it,
00063     // the file descriptor gets closed.  Doh!!!
00064 }
00065 
00066 bool SGSerialPort::open_port(const string& device) {
00067 
00068 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
00069 
00070     fd = CreateFile( device.c_str(),
00071         GENERIC_READ | GENERIC_WRITE,
00072         0, // dwShareMode
00073         NULL, // lpSecurityAttributes
00074         OPEN_EXISTING,
00075         0,
00076         NULL );
00077     if ( fd == INVALID_HANDLE_VALUE )
00078     {
00079         LPVOID lpMsgBuf;
00080         FormatMessage(
00081             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00082             FORMAT_MESSAGE_FROM_SYSTEM | 
00083             FORMAT_MESSAGE_IGNORE_INSERTS,
00084             NULL,
00085             GetLastError(),
00086             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00087             (LPTSTR) &lpMsgBuf,
00088             0,
00089             NULL );
00090 
00091         SG_LOG( SG_IO, SG_ALERT, "Error opening serial device \"" 
00092             << device << "\" " << (const char*) lpMsgBuf );
00093         LocalFree( lpMsgBuf );
00094         return false;
00095     }
00096 
00097     dev_open = true;
00098     return true;
00099 
00100 #else
00101 
00102     struct termios config;
00103 
00104     fd = open(device.c_str(), O_RDWR | O_NOCTTY| O_NDELAY);
00105     SG_LOG( SG_EVENT, SG_DEBUG, "Serial fd created = " << fd);
00106 
00107     if ( fd  == -1 ) {
00108         SG_LOG( SG_IO, SG_ALERT, "Cannot open " << device
00109                 << " for serial I/O" );
00110         return false;
00111     } else {
00112         dev_open = true;
00113     }
00114 
00115     // set required port parameters 
00116     if ( tcgetattr( fd, &config ) != 0 ) {
00117         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
00118         return false;
00119     }
00120 
00121     // cfmakeraw( &config );
00122 
00123     // cout << "config.c_iflag = " << config.c_iflag << endl;
00124 
00125     // disable LF expanded to CR-LF
00126     config.c_oflag &= ~(ONLCR);
00127 
00128     // disable software flow control
00129     config.c_iflag &= ~(IXON | IXOFF | IXANY);
00130 
00131     // enable the receiver and set local mode
00132     config.c_cflag |= (CLOCAL | CREAD);
00133 
00134 #if !defined( sgi ) && !defined(_AIX)
00135     // disable hardware flow control
00136     config.c_cflag &= ~(CRTSCTS);
00137 #endif
00138 
00139     // cout << "config.c_iflag = " << config.c_iflag << endl;
00140     
00141     // Raw (not cooked/canonical) input mode
00142     config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
00143 
00144     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
00145         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
00146         return false;
00147     }
00148 
00149     return true;
00150 #endif
00151 }
00152 
00153 
00154 bool SGSerialPort::close_port() {
00155 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
00156     CloseHandle( fd );
00157 #else
00158     close(fd);
00159 #endif
00160 
00161     dev_open = false;
00162 
00163     return true;
00164 }
00165 
00166 
00167 bool SGSerialPort::set_baud(int baud) {
00168 
00169 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
00170 
00171     DCB dcb;
00172     if ( GetCommState( fd, &dcb ) ) {
00173         dcb.BaudRate = baud;
00174         dcb.fOutxCtsFlow = FALSE;
00175         dcb.fOutxDsrFlow = FALSE;
00176         dcb.fOutX = TRUE;
00177         dcb.fInX = TRUE;
00178 
00179         if ( !SetCommState( fd, &dcb ) ) {
00180             LPVOID lpMsgBuf;
00181             FormatMessage(
00182                 FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00183                 FORMAT_MESSAGE_FROM_SYSTEM | 
00184                 FORMAT_MESSAGE_IGNORE_INSERTS,
00185                 NULL,
00186                 GetLastError(),
00187                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00188                 (LPTSTR) &lpMsgBuf,
00189                 0,
00190                 NULL );
00191 
00192             SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings: " 
00193                 << (const char*) lpMsgBuf );
00194             LocalFree( lpMsgBuf );
00195             return false;
00196         }
00197     } else {
00198         LPVOID lpMsgBuf;
00199         FormatMessage(
00200             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00201             FORMAT_MESSAGE_FROM_SYSTEM | 
00202             FORMAT_MESSAGE_IGNORE_INSERTS,
00203             NULL,
00204             GetLastError(),
00205             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00206             (LPTSTR) &lpMsgBuf,
00207             0,
00208             NULL );
00209 
00210         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings: " 
00211              << (const char*) lpMsgBuf );
00212         LocalFree( lpMsgBuf );
00213         return false;
00214     }
00215 
00216     return true;
00217 
00218 #else
00219 
00220     struct termios config;
00221     speed_t speed = B9600;
00222 
00223     if ( tcgetattr( fd, &config ) != 0 ) {
00224         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
00225         return false;
00226     }
00227 
00228     if ( baud == 300 ) {
00229         speed = B300;
00230     } else if ( baud == 1200 ) {
00231         speed = B1200;
00232     } else if ( baud == 2400 ) {
00233         speed = B2400;
00234     } else if ( baud == 4800 ) {
00235         speed = B4800;
00236     } else if ( baud == 9600 ) {
00237         speed = B9600;
00238     } else if ( baud == 19200 ) {
00239         speed = B19200;
00240     } else if ( baud == 38400 ) {
00241         speed = B38400;
00242 #if defined( linux ) || defined( __FreeBSD__ )
00243     } else if ( baud == 57600 ) {
00244         speed = B57600;
00245     } else if ( baud == 115200 ) {
00246         speed = B115200;
00247     } else if ( baud == 230400 ) {
00248         speed = B230400;
00249 #endif
00250     } else {
00251         SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
00252         return false;
00253     }
00254 
00255     if ( cfsetispeed( &config, speed ) != 0 ) {
00256         SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
00257         return false;
00258     }
00259 
00260     if ( cfsetospeed( &config, speed ) != 0 ) {
00261         SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
00262         return false;
00263     }
00264 
00265     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
00266         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
00267         return false;
00268     }
00269 
00270     return true;
00271 
00272 #endif
00273 
00274 }
00275 
00276 string SGSerialPort::read_port() {
00277 
00278     const int max_count = 1024;
00279     char buffer[max_count+1];
00280     string result;
00281 
00282 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
00283 
00284     DWORD count;
00285     if ( ReadFile( fd, buffer, max_count, &count, 0 ) ) {
00286         buffer[count] = '\0';
00287         result = buffer;
00288     } else {
00289         LPVOID lpMsgBuf;
00290         FormatMessage(
00291             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00292             FORMAT_MESSAGE_FROM_SYSTEM | 
00293             FORMAT_MESSAGE_IGNORE_INSERTS,
00294             NULL,
00295             GetLastError(),
00296             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00297             (LPTSTR) &lpMsgBuf,
00298             0,
00299             NULL );
00300 
00301         SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: " 
00302              << (const char*) lpMsgBuf );
00303         LocalFree( lpMsgBuf );
00304     }
00305 
00306     return result;
00307 
00308 #else
00309 
00310     int count = read(fd, buffer, max_count);
00311     // cout << "read " << count << " bytes" << endl;
00312 
00313     if ( count < 0 ) {
00314         // error condition
00315         if ( errno != EAGAIN ) {
00316             SG_LOG( SG_IO, SG_ALERT, 
00317                     "Serial I/O on read, error number = " << errno );
00318         }
00319 
00320         return "";
00321     } else {
00322         buffer[count] = '\0';
00323         result = buffer;
00324 
00325         return result;
00326     }
00327 
00328 #endif
00329 
00330 }
00331 
00332 int SGSerialPort::read_port(char *buf, int len) {
00333 
00334 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
00335 
00336     DWORD count;
00337     if ( ReadFile( fd, buf, len, &count, 0 ) ) {
00338         buf[count] = '\0';
00339 
00340         return count;
00341     } else {
00342         LPVOID lpMsgBuf;
00343         FormatMessage(
00344             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00345             FORMAT_MESSAGE_FROM_SYSTEM | 
00346             FORMAT_MESSAGE_IGNORE_INSERTS,
00347             NULL,
00348             GetLastError(),
00349             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00350             (LPTSTR) &lpMsgBuf,
00351             0,
00352             NULL );
00353 
00354         SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: " 
00355              << (const char*) lpMsgBuf );
00356         LocalFree( lpMsgBuf );
00357 
00358         buf[0] = '\0';
00359         return 0;
00360     }
00361 
00362 #else
00363 
00364     string result;
00365 
00366     int count = read(fd, buf, len);
00367     // cout << "read " << count << " bytes" << endl;
00368 
00369     if ( count < 0 ) {
00370         // error condition
00371         if ( errno != EAGAIN ) {
00372             SG_LOG( SG_IO, SG_ALERT, 
00373                     "Serial I/O on read, error number = " << errno );
00374         }
00375 
00376         buf[0] = '\0';
00377         return 0;
00378     } else {
00379         buf[count] = '\0';
00380 
00381         return count;
00382     }
00383 
00384 #endif
00385 
00386 }
00387 
00388 
00389 int SGSerialPort::write_port(const string& value) {
00390 
00391 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
00392 
00393     LPCVOID lpBuffer = value.data();
00394     DWORD nNumberOfBytesToWrite = value.length();
00395     DWORD lpNumberOfBytesWritten;
00396 
00397     if ( WriteFile( fd,
00398         lpBuffer,
00399         nNumberOfBytesToWrite,
00400         &lpNumberOfBytesWritten,
00401         0 ) == 0 )
00402     {
00403         LPVOID lpMsgBuf;
00404         FormatMessage(
00405             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00406             FORMAT_MESSAGE_FROM_SYSTEM | 
00407             FORMAT_MESSAGE_IGNORE_INSERTS,
00408             NULL,
00409             GetLastError(),
00410             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00411             (LPTSTR) &lpMsgBuf,
00412             0,
00413             NULL );
00414 
00415         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
00416              << (const char*) lpMsgBuf );
00417         LocalFree( lpMsgBuf );
00418         return int(lpNumberOfBytesWritten);
00419     }
00420 
00421     return int(lpNumberOfBytesWritten);
00422 
00423 #else
00424 
00425     static bool error = false;
00426     int count;
00427 
00428     if ( error ) {
00429         SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
00430         // attempt some sort of error recovery
00431         count = write(fd, "\n", 1);
00432         if ( count == 1 ) {
00433             // cout << "Serial error recover successful!\n";
00434             error = false;
00435         } else {
00436             return 0;
00437         }
00438     }
00439 
00440     count = write(fd, value.c_str(), value.length());
00441     // cout << "write '" << value << "'  " << count << " bytes" << endl;
00442 
00443     if ( (int)count == (int)value.length() ) {
00444         error = false;
00445     } else {
00446         if ( errno == EAGAIN ) {
00447             // ok ... in our context we don't really care if we can't
00448             // write a string, we'll just get it the next time around
00449             error = false;
00450         } else {
00451             error = true;
00452             SG_LOG( SG_IO, SG_ALERT,
00453                     "Serial I/O on write, error number = " << errno );
00454         }
00455     }
00456 
00457     return count;
00458 
00459 #endif
00460 
00461 }
00462 
00463 
00464 int SGSerialPort::write_port(const char* buf, int len) {
00465 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
00466 
00467     LPCVOID lpBuffer = buf;
00468     DWORD nNumberOfBytesToWrite = len;
00469     DWORD lpNumberOfBytesWritten;
00470 
00471     if ( WriteFile( fd,
00472         lpBuffer,
00473         nNumberOfBytesToWrite,
00474         &lpNumberOfBytesWritten,
00475         0 ) == 0 )
00476     {
00477         LPVOID lpMsgBuf;
00478         FormatMessage(
00479             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00480             FORMAT_MESSAGE_FROM_SYSTEM | 
00481             FORMAT_MESSAGE_IGNORE_INSERTS,
00482             NULL,
00483             GetLastError(),
00484             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00485             (LPTSTR) &lpMsgBuf,
00486             0,
00487             NULL );
00488 
00489         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
00490              << (const char*) lpMsgBuf );
00491         LocalFree( lpMsgBuf );
00492         return int(lpNumberOfBytesWritten);
00493     }
00494 
00495     return int(lpNumberOfBytesWritten);
00496 
00497 #else
00498 
00499     static bool error = false;
00500     int count;
00501 
00502     if ( error ) {
00503         // attempt some sort of error recovery
00504         count = write(fd, "\n", 1);
00505         if ( count == 1 ) {
00506             // cout << "Serial error recover successful!\n";
00507             error = false;
00508         } else {
00509             return 0;
00510         }
00511     }
00512 
00513     count = write(fd, buf, len);
00514     // cout << "write '" << buf << "'  " << count << " bytes" << endl;
00515 
00516     if ( (int)count == len ) {
00517         error = false;
00518     } else {
00519         error = true;
00520         if ( errno == EAGAIN ) {
00521             // ok ... in our context we don't really care if we can't
00522             // write a string, we'll just get it the next time around
00523         } else {
00524             SG_LOG( SG_IO, SG_ALERT,
00525                     "Serial I/O on write, error number = " << errno );
00526         }
00527     }
00528 
00529     return count;
00530 
00531 #endif
00532 
00533 }

Generated on Mon Dec 17 09:30:55 2007 for SimGear by  doxygen 1.5.1