1 // serial.cxx -- Unix serial I/O support
3 // Written by Curtis Olson, started November 1998.
5 // Copyright (C) 1998 Curtis L. Olson - curt@flightgear.org
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 Library General Public
18 // License along with this library; if not, write to the
19 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 // Boston, MA 02111-1307, USA.
29 #include <simgear/compiler.h>
31 #ifdef FG_HAVE_STD_INCLUDE
37 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
38 // maybe include something???
41 # include <sys/types.h>
42 # include <sys/stat.h>
47 #include <simgear/debug/logstream.hxx>
52 FGSerialPort::FGSerialPort()
58 FGSerialPort::FGSerialPort(const string& device, int baud) {
66 FGSerialPort::~FGSerialPort() {
67 // closing the port here screws us up because if we would even so
68 // much as make a copy of an FGSerialPort object and then delete it,
69 // the file descriptor gets closed. Doh!!!
72 bool FGSerialPort::open_port(const string& device) {
74 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
76 fd = CreateFile( device.c_str(),
77 GENERIC_READ | GENERIC_WRITE,
79 NULL, // lpSecurityAttributes
83 if ( fd == INVALID_HANDLE_VALUE )
87 FORMAT_MESSAGE_ALLOCATE_BUFFER |
88 FORMAT_MESSAGE_FROM_SYSTEM |
89 FORMAT_MESSAGE_IGNORE_INSERTS,
92 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
97 FG_LOG( FG_IO, FG_ALERT, "Error opening serial device \""
98 << device << "\" " << (const char*) lpMsgBuf );
99 LocalFree( lpMsgBuf );
108 struct termios config;
110 fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
111 cout << "Serial fd created = " << fd << endl;
114 FG_LOG( FG_IO, FG_ALERT, "Cannot open " << device
115 << " for serial I/O" );
121 // set required port parameters
122 if ( tcgetattr( fd, &config ) != 0 ) {
123 FG_LOG( FG_IO, FG_ALERT, "Unable to poll port settings" );
127 // cfmakeraw( &config );
129 // cout << "config.c_iflag = " << config.c_iflag << endl;
131 // software flow control on
132 config.c_iflag |= IXON;
133 // config.c_iflag |= IXOFF;
135 // config.c_cflag |= CLOCAL;
138 // disable hardware flow control
139 config.c_cflag &= ~(CRTSCTS);
142 // cout << "config.c_iflag = " << config.c_iflag << endl;
144 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
145 FG_LOG( FG_IO, FG_ALERT, "Unable to update port settings" );
154 bool FGSerialPort::close_port() {
155 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
167 bool FGSerialPort::set_baud(int baud) {
169 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
175 struct termios config;
176 speed_t speed = B9600;
178 if ( tcgetattr( fd, &config ) != 0 ) {
179 FG_LOG( FG_IO, FG_ALERT, "Unable to poll port settings" );
185 } else if ( baud == 1200 ) {
187 } else if ( baud == 2400 ) {
189 } else if ( baud == 4800 ) {
191 } else if ( baud == 9600 ) {
193 } else if ( baud == 19200 ) {
195 } else if ( baud == 38400 ) {
197 } else if ( baud == 57600 ) {
199 } else if ( baud == 115200 ) {
201 #if defined( linux ) || defined( __FreeBSD__ )
202 } else if ( baud == 230400 ) {
206 FG_LOG( FG_IO, FG_ALERT, "Unsupported baud rate " << baud );
210 if ( cfsetispeed( &config, speed ) != 0 ) {
211 FG_LOG( FG_IO, FG_ALERT, "Problem setting input baud rate" );
215 if ( cfsetospeed( &config, speed ) != 0 ) {
216 FG_LOG( FG_IO, FG_ALERT, "Problem setting output baud rate" );
220 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
221 FG_LOG( FG_IO, FG_ALERT, "Unable to update port settings" );
231 string FGSerialPort::read_port() {
233 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
240 const int max_count = 1024;
241 char buffer[max_count+1];
245 count = read(fd, buffer, max_count);
246 // cout << "read " << count << " bytes" << endl;
250 if ( errno != EAGAIN ) {
251 FG_LOG( FG_IO, FG_ALERT,
252 "Serial I/O on read, error number = " << errno );
257 buffer[count] = '\0';
267 int FGSerialPort::read_port(char *buf, int len) {
269 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
278 int count = read(fd, buf, len);
279 // cout << "read " << count << " bytes" << endl;
283 if ( errno != EAGAIN ) {
284 FG_LOG( FG_IO, FG_ALERT,
285 "Serial I/O on read, error number = " << errno );
301 int FGSerialPort::write_port(const string& value) {
303 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
305 LPCVOID lpBuffer = value.c_str();
306 DWORD nNumberOfBytesToWrite = value.length();
307 DWORD lpNumberOfBytesWritten;
308 OVERLAPPED lpOverlapped;
312 nNumberOfBytesToWrite,
313 &lpNumberOfBytesWritten,
314 &lpOverlapped ) == 0 )
318 FORMAT_MESSAGE_ALLOCATE_BUFFER |
319 FORMAT_MESSAGE_FROM_SYSTEM |
320 FORMAT_MESSAGE_IGNORE_INSERTS,
323 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
328 FG_LOG( FG_IO, FG_ALERT, "Serial I/O write error: "
329 << (const char*) lpMsgBuf );
330 LocalFree( lpMsgBuf );
331 return int(lpNumberOfBytesWritten);
334 return int(lpNumberOfBytesWritten);
338 static bool error = false;
342 FG_LOG( FG_IO, FG_ALERT, "attempting serial write error recovery" );
343 // attempt some sort of error recovery
344 count = write(fd, "\n", 1);
346 // cout << "Serial error recover successful!\n";
353 count = write(fd, value.c_str(), value.length());
354 // cout << "write '" << value << "' " << count << " bytes" << endl;
356 if ( (int)count == (int)value.length() ) {
359 if ( errno == EAGAIN ) {
360 // ok ... in our context we don't really care if we can't
361 // write a string, we'll just get it the next time around
365 FG_LOG( FG_IO, FG_ALERT,
366 "Serial I/O on write, error number = " << errno );
377 int FGSerialPort::write_port(const char* buf, int len) {
378 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
380 LPCVOID lpBuffer = buf;
381 DWORD nNumberOfBytesToWrite = len;
382 DWORD lpNumberOfBytesWritten;
383 OVERLAPPED lpOverlapped;
387 nNumberOfBytesToWrite,
388 &lpNumberOfBytesWritten,
389 &lpOverlapped ) == 0 )
393 FORMAT_MESSAGE_ALLOCATE_BUFFER |
394 FORMAT_MESSAGE_FROM_SYSTEM |
395 FORMAT_MESSAGE_IGNORE_INSERTS,
398 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
403 FG_LOG( FG_IO, FG_ALERT, "Serial I/O write error: "
404 << (const char*) lpMsgBuf );
405 LocalFree( lpMsgBuf );
406 return int(lpNumberOfBytesWritten);
409 return int(lpNumberOfBytesWritten);
413 static bool error = false;
417 // attempt some sort of error recovery
418 count = write(fd, "\n", 1);
420 // cout << "Serial error recover successful!\n";
427 count = write(fd, buf, len);
428 // cout << "write '" << buf << "' " << count << " bytes" << endl;
430 if ( (int)count == len ) {
434 if ( errno == EAGAIN ) {
435 // ok ... in our context we don't really care if we can't
436 // write a string, we'll just get it the next time around
438 FG_LOG( FG_IO, FG_ALERT,
439 "Serial I/O on write, error number = " << errno );