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.
25 #include <simgear/compiler.h>
27 #ifdef SG_HAVE_STD_INCLUDE
33 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
34 // maybe include something???
37 # include <sys/types.h>
38 # include <sys/stat.h>
43 #include <simgear/debug/logstream.hxx>
48 FGSerialPort::FGSerialPort()
54 FGSerialPort::FGSerialPort(const string& device, int baud) {
62 FGSerialPort::~FGSerialPort() {
63 // closing the port here screws us up because if we would even so
64 // much as make a copy of an FGSerialPort object and then delete it,
65 // the file descriptor gets closed. Doh!!!
68 bool FGSerialPort::open_port(const string& device) {
70 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
72 fd = CreateFile( device.c_str(),
73 GENERIC_READ | GENERIC_WRITE,
75 NULL, // lpSecurityAttributes
79 if ( fd == INVALID_HANDLE_VALUE )
83 FORMAT_MESSAGE_ALLOCATE_BUFFER |
84 FORMAT_MESSAGE_FROM_SYSTEM |
85 FORMAT_MESSAGE_IGNORE_INSERTS,
88 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
93 SG_LOG( SG_IO, SG_ALERT, "Error opening serial device \""
94 << device << "\" " << (const char*) lpMsgBuf );
95 LocalFree( lpMsgBuf );
104 struct termios config;
106 fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
107 cout << "Serial fd created = " << fd << endl;
110 SG_LOG( SG_IO, SG_ALERT, "Cannot open " << device
111 << " for serial I/O" );
117 // set required port parameters
118 if ( tcgetattr( fd, &config ) != 0 ) {
119 SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
123 // cfmakeraw( &config );
125 // cout << "config.c_iflag = " << config.c_iflag << endl;
127 // software flow control on
128 config.c_iflag |= IXON;
129 // config.c_iflag |= IXOFF;
131 // config.c_cflag |= CLOCAL;
134 // disable hardware flow control
135 config.c_cflag &= ~(CRTSCTS);
138 // cout << "config.c_iflag = " << config.c_iflag << endl;
140 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
141 SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
150 bool FGSerialPort::close_port() {
151 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
163 bool FGSerialPort::set_baud(int baud) {
165 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
171 struct termios config;
172 speed_t speed = B9600;
174 if ( tcgetattr( fd, &config ) != 0 ) {
175 SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
181 } else if ( baud == 1200 ) {
183 } else if ( baud == 2400 ) {
185 } else if ( baud == 4800 ) {
187 } else if ( baud == 9600 ) {
189 } else if ( baud == 19200 ) {
191 } else if ( baud == 38400 ) {
193 } else if ( baud == 57600 ) {
195 } else if ( baud == 115200 ) {
197 #if defined( linux ) || defined( __FreeBSD__ )
198 } else if ( baud == 230400 ) {
202 SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
206 if ( cfsetispeed( &config, speed ) != 0 ) {
207 SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
211 if ( cfsetospeed( &config, speed ) != 0 ) {
212 SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
216 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
217 SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
227 string FGSerialPort::read_port() {
229 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
236 const int max_count = 1024;
237 char buffer[max_count+1];
241 count = read(fd, buffer, max_count);
242 // cout << "read " << count << " bytes" << endl;
246 if ( errno != EAGAIN ) {
247 SG_LOG( SG_IO, SG_ALERT,
248 "Serial I/O on read, error number = " << errno );
253 buffer[count] = '\0';
263 int FGSerialPort::read_port(char *buf, int len) {
265 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
274 int count = read(fd, buf, len);
275 // cout << "read " << count << " bytes" << endl;
279 if ( errno != EAGAIN ) {
280 SG_LOG( SG_IO, SG_ALERT,
281 "Serial I/O on read, error number = " << errno );
297 int FGSerialPort::write_port(const string& value) {
299 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
301 LPCVOID lpBuffer = value.c_str();
302 DWORD nNumberOfBytesToWrite = value.length();
303 DWORD lpNumberOfBytesWritten;
304 OVERLAPPED lpOverlapped;
308 nNumberOfBytesToWrite,
309 &lpNumberOfBytesWritten,
310 &lpOverlapped ) == 0 )
314 FORMAT_MESSAGE_ALLOCATE_BUFFER |
315 FORMAT_MESSAGE_FROM_SYSTEM |
316 FORMAT_MESSAGE_IGNORE_INSERTS,
319 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
324 SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
325 << (const char*) lpMsgBuf );
326 LocalFree( lpMsgBuf );
327 return int(lpNumberOfBytesWritten);
330 return int(lpNumberOfBytesWritten);
334 static bool error = false;
338 SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
339 // attempt some sort of error recovery
340 count = write(fd, "\n", 1);
342 // cout << "Serial error recover successful!\n";
349 count = write(fd, value.c_str(), value.length());
350 // cout << "write '" << value << "' " << count << " bytes" << endl;
352 if ( (int)count == (int)value.length() ) {
355 if ( errno == EAGAIN ) {
356 // ok ... in our context we don't really care if we can't
357 // write a string, we'll just get it the next time around
361 SG_LOG( SG_IO, SG_ALERT,
362 "Serial I/O on write, error number = " << errno );
373 int FGSerialPort::write_port(const char* buf, int len) {
374 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
376 LPCVOID lpBuffer = buf;
377 DWORD nNumberOfBytesToWrite = len;
378 DWORD lpNumberOfBytesWritten;
379 OVERLAPPED lpOverlapped;
383 nNumberOfBytesToWrite,
384 &lpNumberOfBytesWritten,
385 &lpOverlapped ) == 0 )
389 FORMAT_MESSAGE_ALLOCATE_BUFFER |
390 FORMAT_MESSAGE_FROM_SYSTEM |
391 FORMAT_MESSAGE_IGNORE_INSERTS,
394 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
399 SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
400 << (const char*) lpMsgBuf );
401 LocalFree( lpMsgBuf );
402 return int(lpNumberOfBytesWritten);
405 return int(lpNumberOfBytesWritten);
409 static bool error = false;
413 // attempt some sort of error recovery
414 count = write(fd, "\n", 1);
416 // cout << "Serial error recover successful!\n";
423 count = write(fd, buf, len);
424 // cout << "write '" << buf << "' " << count << " bytes" << endl;
426 if ( (int)count == len ) {
430 if ( errno == EAGAIN ) {
431 // ok ... in our context we don't really care if we can't
432 // write a string, we'll just get it the next time around
434 SG_LOG( SG_IO, SG_ALERT,
435 "Serial I/O on write, error number = " << errno );