1 // serial.cxx -- Unix serial I/O support
3 // Written by Curtis Olson, started November 1998.
5 // Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Library General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <simgear/compiler.h>
28 #ifdef SG_HAVE_STD_INCLUDE
34 #if !defined( WIN32 ) || defined( __CYGWIN__) || defined( __CYGWIN32__ )
36 # include <sys/types.h>
37 # include <sys/stat.h>
42 #include <simgear/debug/logstream.hxx>
46 SGSerialPort::SGSerialPort()
52 SGSerialPort::SGSerialPort(const string& device, int baud) {
60 SGSerialPort::~SGSerialPort() {
61 // closing the port here screws us up because if we would even so
62 // much as make a copy of an SGSerialPort object and then delete it,
63 // the file descriptor gets closed. Doh!!!
66 bool SGSerialPort::open_port(const string& device) {
68 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
70 fd = CreateFile( device.c_str(),
71 GENERIC_READ | GENERIC_WRITE,
73 NULL, // lpSecurityAttributes
77 if ( fd == INVALID_HANDLE_VALUE )
81 FORMAT_MESSAGE_ALLOCATE_BUFFER |
82 FORMAT_MESSAGE_FROM_SYSTEM |
83 FORMAT_MESSAGE_IGNORE_INSERTS,
86 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
91 SG_LOG( SG_IO, SG_ALERT, "Error opening serial device \""
92 << device << "\" " << (const char*) lpMsgBuf );
93 LocalFree( lpMsgBuf );
102 struct termios config;
104 fd = open(device.c_str(), O_RDWR | O_NOCTTY| O_NDELAY);
105 SG_LOG( SG_EVENT, SG_DEBUG, "Serial fd created = " << fd);
108 SG_LOG( SG_IO, SG_ALERT, "Cannot open " << device
109 << " for serial I/O" );
115 // set required port parameters
116 if ( tcgetattr( fd, &config ) != 0 ) {
117 SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
121 // cfmakeraw( &config );
123 // cout << "config.c_iflag = " << config.c_iflag << endl;
125 // disable LF expanded to CR-LF
126 config.c_oflag &= ~(ONLCR);
128 // disable software flow control
129 config.c_iflag &= ~(IXON | IXOFF | IXANY);
131 // enable the receiver and set local mode
132 config.c_cflag |= (CLOCAL | CREAD);
134 #if !defined( sgi ) && !defined(_AIX)
135 // disable hardware flow control
136 config.c_cflag &= ~(CRTSCTS);
139 // cout << "config.c_iflag = " << config.c_iflag << endl;
141 // Raw (not cooked/canonical) input mode
142 config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
144 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
145 SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
154 bool SGSerialPort::close_port() {
155 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
167 bool SGSerialPort::set_baud(int baud) {
169 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
172 if ( GetCommState( fd, &dcb ) ) {
174 dcb.fOutxCtsFlow = FALSE;
175 dcb.fOutxDsrFlow = FALSE;
179 if ( !SetCommState( fd, &dcb ) ) {
182 FORMAT_MESSAGE_ALLOCATE_BUFFER |
183 FORMAT_MESSAGE_FROM_SYSTEM |
184 FORMAT_MESSAGE_IGNORE_INSERTS,
187 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
192 SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings: "
193 << (const char*) lpMsgBuf );
194 LocalFree( lpMsgBuf );
200 FORMAT_MESSAGE_ALLOCATE_BUFFER |
201 FORMAT_MESSAGE_FROM_SYSTEM |
202 FORMAT_MESSAGE_IGNORE_INSERTS,
205 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
210 SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings: "
211 << (const char*) lpMsgBuf );
212 LocalFree( lpMsgBuf );
220 struct termios config;
221 speed_t speed = B9600;
223 if ( tcgetattr( fd, &config ) != 0 ) {
224 SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
230 } else if ( baud == 1200 ) {
232 } else if ( baud == 2400 ) {
234 } else if ( baud == 4800 ) {
236 } else if ( baud == 9600 ) {
238 } else if ( baud == 19200 ) {
240 } else if ( baud == 38400 ) {
242 #if defined( linux ) || defined( __FreeBSD__ )
243 } else if ( baud == 57600 ) {
245 } else if ( baud == 115200 ) {
247 } else if ( baud == 230400 ) {
251 SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
255 if ( cfsetispeed( &config, speed ) != 0 ) {
256 SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
260 if ( cfsetospeed( &config, speed ) != 0 ) {
261 SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
265 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
266 SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
276 string SGSerialPort::read_port() {
278 const int max_count = 1024;
279 char buffer[max_count+1];
282 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
285 if ( ReadFile( fd, buffer, max_count, &count, 0 ) ) {
286 buffer[count] = '\0';
291 FORMAT_MESSAGE_ALLOCATE_BUFFER |
292 FORMAT_MESSAGE_FROM_SYSTEM |
293 FORMAT_MESSAGE_IGNORE_INSERTS,
296 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
301 SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: "
302 << (const char*) lpMsgBuf );
303 LocalFree( lpMsgBuf );
310 int count = read(fd, buffer, max_count);
311 // cout << "read " << count << " bytes" << endl;
315 if ( errno != EAGAIN ) {
316 SG_LOG( SG_IO, SG_ALERT,
317 "Serial I/O on read, error number = " << errno );
322 buffer[count] = '\0';
332 int SGSerialPort::read_port(char *buf, int len) {
334 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
337 if ( ReadFile( fd, buf, len, &count, 0 ) ) {
344 FORMAT_MESSAGE_ALLOCATE_BUFFER |
345 FORMAT_MESSAGE_FROM_SYSTEM |
346 FORMAT_MESSAGE_IGNORE_INSERTS,
349 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
354 SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: "
355 << (const char*) lpMsgBuf );
356 LocalFree( lpMsgBuf );
366 int count = read(fd, buf, len);
367 // cout << "read " << count << " bytes" << endl;
371 if ( errno != EAGAIN ) {
372 SG_LOG( SG_IO, SG_ALERT,
373 "Serial I/O on read, error number = " << errno );
389 int SGSerialPort::write_port(const string& value) {
391 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
393 LPCVOID lpBuffer = value.data();
394 DWORD nNumberOfBytesToWrite = value.length();
395 DWORD lpNumberOfBytesWritten;
399 nNumberOfBytesToWrite,
400 &lpNumberOfBytesWritten,
405 FORMAT_MESSAGE_ALLOCATE_BUFFER |
406 FORMAT_MESSAGE_FROM_SYSTEM |
407 FORMAT_MESSAGE_IGNORE_INSERTS,
410 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
415 SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
416 << (const char*) lpMsgBuf );
417 LocalFree( lpMsgBuf );
418 return int(lpNumberOfBytesWritten);
421 return int(lpNumberOfBytesWritten);
425 static bool error = false;
429 SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
430 // attempt some sort of error recovery
431 count = write(fd, "\n", 1);
433 // cout << "Serial error recover successful!\n";
440 count = write(fd, value.c_str(), value.length());
441 // cout << "write '" << value << "' " << count << " bytes" << endl;
443 if ( (int)count == (int)value.length() ) {
446 if ( errno == EAGAIN ) {
447 // ok ... in our context we don't really care if we can't
448 // write a string, we'll just get it the next time around
452 SG_LOG( SG_IO, SG_ALERT,
453 "Serial I/O on write, error number = " << errno );
464 int SGSerialPort::write_port(const char* buf, int len) {
465 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
467 LPCVOID lpBuffer = buf;
468 DWORD nNumberOfBytesToWrite = len;
469 DWORD lpNumberOfBytesWritten;
473 nNumberOfBytesToWrite,
474 &lpNumberOfBytesWritten,
479 FORMAT_MESSAGE_ALLOCATE_BUFFER |
480 FORMAT_MESSAGE_FROM_SYSTEM |
481 FORMAT_MESSAGE_IGNORE_INSERTS,
484 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
489 SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
490 << (const char*) lpMsgBuf );
491 LocalFree( lpMsgBuf );
492 return int(lpNumberOfBytesWritten);
495 return int(lpNumberOfBytesWritten);
499 static bool error = false;
503 // attempt some sort of error recovery
504 count = write(fd, "\n", 1);
506 // cout << "Serial error recover successful!\n";
513 count = write(fd, buf, len);
514 // cout << "write '" << buf << "' " << count << " bytes" << endl;
516 if ( (int)count == len ) {
520 if ( errno == EAGAIN ) {
521 // ok ... in our context we don't really care if we can't
522 // write a string, we'll just get it the next time around
524 SG_LOG( SG_IO, SG_ALERT,
525 "Serial I/O on write, error number = " << errno );