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 program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // 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., 675 Mass Ave, Cambridge, MA 02139, USA.
22 // (Log is kept at end of this file)
29 #include "Include/compiler.h"
30 #ifdef FG_HAVE_STD_INCLUDE
36 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
37 // maybe include something???
40 # include <sys/types.h>
41 # include <sys/stat.h>
46 #include <Debug/logstream.hxx>
57 fgSERIAL::fgSERIAL(const string& device, int baud) {
65 fgSERIAL::~fgSERIAL() {
66 // closing the port here screws us up because if we would even so
67 // much as make a copy of an fgSERIAL object and then delete it,
68 // the file descriptor gets closed. Doh!!!
71 bool fgSERIAL::open_port(const string& device) {
73 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
75 fd = CreateFile( device.c_str(),
76 GENERIC_READ | GENERIC_WRITE,
78 NULL, // lpSecurityAttributes
82 if ( fd == INVALID_HANDLE_VALUE )
86 FORMAT_MESSAGE_ALLOCATE_BUFFER |
87 FORMAT_MESSAGE_FROM_SYSTEM |
88 FORMAT_MESSAGE_IGNORE_INSERTS,
91 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
96 FG_LOG( FG_SERIAL, FG_ALERT, "Error opening serial device \""
97 << device << "\" " << (const char*) lpMsgBuf );
98 LocalFree( lpMsgBuf );
107 struct termios config;
109 fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
110 cout << "Serial fd created = " << fd << endl;
113 FG_LOG( FG_SERIAL, FG_ALERT, "Cannot open " << device
114 << " for serial I/O" );
120 // set required port parameters
121 if ( tcgetattr( fd, &config ) != 0 ) {
122 FG_LOG( FG_SERIAL, FG_ALERT, "Unable to poll port settings" );
126 // cfmakeraw( &config );
128 // cout << "config.c_iflag = " << config.c_iflag << endl;
130 // software flow control on
131 config.c_iflag |= IXON;
132 // config.c_iflag |= IXOFF;
134 // config.c_cflag |= CLOCAL;
137 // disable hardware flow control
138 config.c_cflag &= ~(CRTSCTS);
141 // cout << "config.c_iflag = " << config.c_iflag << endl;
143 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
144 FG_LOG( FG_SERIAL, FG_ALERT, "Unable to update port settings" );
153 bool fgSERIAL::close_port() {
154 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
164 bool fgSERIAL::set_baud(int baud) {
166 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
172 struct termios config;
173 speed_t speed = B9600;
175 if ( tcgetattr( fd, &config ) != 0 ) {
176 FG_LOG( FG_SERIAL, FG_ALERT, "Unable to poll port settings" );
182 } else if ( baud == 1200 ) {
184 } else if ( baud == 2400 ) {
186 } else if ( baud == 4800 ) {
188 } else if ( baud == 9600 ) {
190 } else if ( baud == 19200 ) {
192 } else if ( baud == 38400 ) {
194 } else if ( baud == 57600 ) {
196 } else if ( baud == 115200 ) {
198 #if defined( linux ) || defined( __FreeBSD__ )
199 } else if ( baud == 230400 ) {
203 FG_LOG( FG_SERIAL, FG_ALERT, "Unsupported baud rate " << baud );
207 if ( cfsetispeed( &config, speed ) != 0 ) {
208 FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting input baud rate" );
212 if ( cfsetospeed( &config, speed ) != 0 ) {
213 FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting output baud rate" );
217 if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
218 FG_LOG( FG_SERIAL, FG_ALERT, "Unable to update port settings" );
228 string fgSERIAL::read_port() {
230 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
237 const int max_count = 1024;
238 char buffer[max_count+1];
242 count = read(fd, buffer, max_count);
243 // cout << "read " << count << " bytes" << endl;
247 if ( errno != EAGAIN ) {
248 FG_LOG( FG_SERIAL, FG_ALERT,
249 "Serial I/O on read, error number = " << errno );
254 buffer[count] = '\0';
264 int fgSERIAL::write_port(const string& value) {
266 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
268 LPCVOID lpBuffer = value.c_str();
269 DWORD nNumberOfBytesToWrite = value.length();
270 DWORD lpNumberOfBytesWritten;
271 OVERLAPPED lpOverlapped;
275 nNumberOfBytesToWrite,
276 &lpNumberOfBytesWritten,
277 &lpOverlapped ) == 0 )
281 FORMAT_MESSAGE_ALLOCATE_BUFFER |
282 FORMAT_MESSAGE_FROM_SYSTEM |
283 FORMAT_MESSAGE_IGNORE_INSERTS,
286 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
291 FG_LOG( FG_SERIAL, FG_ALERT, "Serial I/O write error: "
292 << (const char*) lpMsgBuf );
293 LocalFree( lpMsgBuf );
294 return int(lpNumberOfBytesWritten);
297 return int(lpNumberOfBytesWritten);
301 static bool error = false;
305 // attempt some sort of error recovery
306 count = write(fd, "\n", 1);
308 // cout << "Serial error recover successful!\n";
315 count = write(fd, value.c_str(), value.length());
316 // cout << "write '" << value << "' " << count << " bytes" << endl;
318 if ( (int)count == (int)value.length() ) {
322 if ( errno == EAGAIN ) {
323 // ok ... in our context we don't really care if we can't
324 // write a string, we'll just get it the next time around
326 FG_LOG( FG_SERIAL, FG_ALERT,
327 "Serial I/O on write, error number = " << errno );
339 // Revision 1.9 1999/02/02 20:13:23 curt
340 // MSVC++ portability changes by Bernie Bright:
342 // Lib/Serial/serial.[ch]xx: Initial Windows support - incomplete.
343 // Simulator/Astro/stars.cxx: typo? included <stdio> instead of <cstdio>
344 // Simulator/Cockpit/hud.cxx: Added Standard headers
345 // Simulator/Cockpit/panel.cxx: Redefinition of default parameter
346 // Simulator/Flight/flight.cxx: Replaced cout with FG_LOG. Deleted <stdio.h>
347 // Simulator/Main/fg_init.cxx:
348 // Simulator/Main/GLUTmain.cxx:
349 // Simulator/Main/options.hxx: Shuffled <fg_serial.hxx> dependency
350 // Simulator/Objects/material.hxx:
351 // Simulator/Time/timestamp.hxx: VC++ friend kludge
352 // Simulator/Scenery/tile.[ch]xx: Fixed using std::X declarations
353 // Simulator/Main/views.hxx: Added a constant
355 // Revision 1.8 1999/01/20 13:42:21 curt
356 // Tweaked FDM interface.
357 // Testing check sum support for NMEA serial output.
359 // Revision 1.7 1998/12/04 01:24:35 curt
360 // Tweak for SGI portability.
362 // Revision 1.6 1998/11/30 17:15:29 curt
363 // Having the class destructor close the fd was a bad idea ... especially if you
364 // ever make a copy of the instance and then subsequently destroy either.
365 // close_port() is now a separate member function.
367 // Revision 1.5 1998/11/25 01:33:23 curt
368 // Remove call to cfmakeraw()
370 // Revision 1.4 1998/11/23 21:47:00 curt
371 // Cygnus tools compatibility tweaks.
373 // Revision 1.3 1998/11/19 13:52:54 curt
374 // port configuration tweaks & experiments.
376 // Revision 1.2 1998/11/19 03:35:43 curt
379 // Revision 1.1 1998/11/16 13:53:02 curt