1998-11-16 21:53:01 +08:00
|
|
|
// serial.cxx -- Unix serial I/O support
|
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started November 1998.
|
|
|
|
//
|
|
|
|
// Copyright (C) 1998 Curtis L. Olson - curt@flightgear.org
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
// (Log is kept at end of this file)
|
|
|
|
|
|
|
|
|
1998-11-24 05:47:00 +08:00
|
|
|
#include <errno.h>
|
1998-11-16 21:53:01 +08:00
|
|
|
#include <termios.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <Debug/logstream.hxx>
|
|
|
|
|
|
|
|
#include "serial.hxx"
|
|
|
|
|
|
|
|
|
|
|
|
fgSERIAL::fgSERIAL() {
|
|
|
|
dev_open = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fgSERIAL::fgSERIAL(const string& device, int baud) {
|
|
|
|
open_port(device);
|
|
|
|
|
|
|
|
if ( dev_open ) {
|
|
|
|
set_baud(baud);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fgSERIAL::~fgSERIAL() {
|
1998-12-01 01:15:29 +08:00
|
|
|
// closing the port here screws us up because if we would even so
|
|
|
|
// much as make a copy of an fgSERIAL object and then delete it,
|
|
|
|
// the file descriptor gets closed. Doh!!!
|
|
|
|
|
|
|
|
// close(fd);
|
1998-11-16 21:53:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool fgSERIAL::open_port(const string& device) {
|
1998-11-19 11:35:43 +08:00
|
|
|
struct termios config;
|
|
|
|
|
1998-12-01 01:15:29 +08:00
|
|
|
fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
|
|
|
|
cout << "Serial fd created = " << fd << endl;
|
|
|
|
|
|
|
|
if ( fd == -1 ) {
|
1998-11-16 21:53:01 +08:00
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Cannot open " << device
|
|
|
|
<< " for serial I/O" );
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
dev_open = true;
|
|
|
|
}
|
1998-11-19 11:35:43 +08:00
|
|
|
|
1998-11-19 21:52:54 +08:00
|
|
|
// set required port parameters
|
1998-11-19 11:35:43 +08:00
|
|
|
if ( tcgetattr( fd, &config ) != 0 ) {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Unable to poll port settings" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
1998-11-25 09:33:23 +08:00
|
|
|
// cfmakeraw( &config );
|
1998-11-19 21:52:54 +08:00
|
|
|
|
|
|
|
// cout << "config.c_iflag = " << config.c_iflag << endl;
|
|
|
|
|
|
|
|
// software flow control on
|
1998-12-01 01:15:29 +08:00
|
|
|
config.c_iflag |= IXON;
|
1998-12-04 09:24:35 +08:00
|
|
|
// config.c_iflag |= IXOFF;
|
1998-12-01 01:15:29 +08:00
|
|
|
|
|
|
|
// config.c_cflag |= CLOCAL;
|
1998-11-19 21:52:54 +08:00
|
|
|
|
1998-12-04 09:24:35 +08:00
|
|
|
#if ! defined( sgi )
|
1998-11-19 21:52:54 +08:00
|
|
|
// disable hardware flow control
|
1998-12-01 01:15:29 +08:00
|
|
|
config.c_cflag &= ~(CRTSCTS);
|
1998-12-04 09:24:35 +08:00
|
|
|
#endif
|
1998-11-19 21:52:54 +08:00
|
|
|
|
|
|
|
// cout << "config.c_iflag = " << config.c_iflag << endl;
|
1998-11-19 11:35:43 +08:00
|
|
|
|
|
|
|
if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Unable to update port settings" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
1998-11-16 21:53:01 +08:00
|
|
|
}
|
|
|
|
|
1998-12-01 01:15:29 +08:00
|
|
|
|
|
|
|
bool fgSERIAL::close_port() {
|
|
|
|
close(fd);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-11-16 21:53:01 +08:00
|
|
|
bool fgSERIAL::set_baud(int baud) {
|
|
|
|
struct termios config;
|
1998-11-24 05:47:00 +08:00
|
|
|
speed_t speed = B9600;
|
1998-11-16 21:53:01 +08:00
|
|
|
|
|
|
|
if ( tcgetattr( fd, &config ) != 0 ) {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Unable to poll port settings" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( baud == 300 ) {
|
|
|
|
speed = B300;
|
|
|
|
} else if ( baud == 1200 ) {
|
|
|
|
speed = B1200;
|
|
|
|
} else if ( baud == 2400 ) {
|
|
|
|
speed = B2400;
|
|
|
|
} else if ( baud == 4800 ) {
|
|
|
|
speed = B4800;
|
|
|
|
} else if ( baud == 9600 ) {
|
|
|
|
speed = B9600;
|
|
|
|
} else if ( baud == 19200 ) {
|
|
|
|
speed = B19200;
|
|
|
|
} else if ( baud == 38400 ) {
|
|
|
|
speed = B38400;
|
|
|
|
} else if ( baud == 57600 ) {
|
|
|
|
speed = B57600;
|
|
|
|
} else if ( baud == 115200 ) {
|
|
|
|
speed = B115200;
|
1998-11-24 05:47:00 +08:00
|
|
|
#if defined( linux ) || defined( __FreeBSD__ )
|
1998-11-16 21:53:01 +08:00
|
|
|
} else if ( baud == 230400 ) {
|
|
|
|
speed = B230400;
|
1998-11-24 05:47:00 +08:00
|
|
|
#endif
|
1998-11-16 21:53:01 +08:00
|
|
|
} else {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Unsupported baud rate " << baud );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( cfsetispeed( &config, speed ) != 0 ) {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting input baud rate" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( cfsetospeed( &config, speed ) != 0 ) {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting output baud rate" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT, "Unable to update port settings" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
string fgSERIAL::read_port() {
|
|
|
|
const int max_count = 1024;
|
|
|
|
char buffer[max_count+1];
|
|
|
|
int count;
|
|
|
|
string result;
|
|
|
|
|
|
|
|
count = read(fd, buffer, max_count);
|
|
|
|
// cout << "read " << count << " bytes" << endl;
|
|
|
|
|
|
|
|
if ( count < 0 ) {
|
|
|
|
// error condition
|
|
|
|
if ( errno != EAGAIN ) {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT,
|
|
|
|
"Serial I/O on read, error number = " << errno );
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
} else {
|
|
|
|
buffer[count] = '\0';
|
|
|
|
result = buffer;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int fgSERIAL::write_port(const string& value) {
|
1999-01-20 21:42:21 +08:00
|
|
|
static bool error = false;
|
1998-11-16 21:53:01 +08:00
|
|
|
int count;
|
|
|
|
|
1999-01-20 21:42:21 +08:00
|
|
|
if ( error ) {
|
|
|
|
// attempt some sort of error recovery
|
|
|
|
count = write(fd, "\n", 1);
|
|
|
|
if ( count == 1 ) {
|
|
|
|
// cout << "Serial error recover successful!\n";
|
|
|
|
error = false;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-11-16 21:53:01 +08:00
|
|
|
count = write(fd, value.c_str(), value.length());
|
|
|
|
// cout << "write '" << value << "' " << count << " bytes" << endl;
|
|
|
|
|
1999-01-20 21:42:21 +08:00
|
|
|
if ( (int)count == (int)value.length() ) {
|
|
|
|
error = false;
|
|
|
|
} else {
|
|
|
|
error = true;
|
1998-12-01 01:15:29 +08:00
|
|
|
if ( errno == EAGAIN ) {
|
|
|
|
// ok ... in our context we don't really care if we can't
|
|
|
|
// write a string, we'll just get it the next time around
|
|
|
|
} else {
|
|
|
|
FG_LOG( FG_SERIAL, FG_ALERT,
|
|
|
|
"Serial I/O on write, error number = " << errno );
|
|
|
|
}
|
1998-11-16 21:53:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// $Log$
|
1999-01-20 21:42:21 +08:00
|
|
|
// Revision 1.8 1999/01/20 13:42:21 curt
|
|
|
|
// Tweaked FDM interface.
|
|
|
|
// Testing check sum support for NMEA serial output.
|
|
|
|
//
|
1998-12-04 09:24:35 +08:00
|
|
|
// Revision 1.7 1998/12/04 01:24:35 curt
|
|
|
|
// Tweak for SGI portability.
|
|
|
|
//
|
1998-12-01 01:15:29 +08:00
|
|
|
// Revision 1.6 1998/11/30 17:15:29 curt
|
|
|
|
// Having the class destructor close the fd was a bad idea ... especially if you
|
|
|
|
// ever make a copy of the instance and then subsequently destroy either.
|
|
|
|
// close_port() is now a separate member function.
|
|
|
|
//
|
1998-11-25 09:33:23 +08:00
|
|
|
// Revision 1.5 1998/11/25 01:33:23 curt
|
|
|
|
// Remove call to cfmakeraw()
|
|
|
|
//
|
1998-11-24 05:47:00 +08:00
|
|
|
// Revision 1.4 1998/11/23 21:47:00 curt
|
|
|
|
// Cygnus tools compatibility tweaks.
|
|
|
|
//
|
1998-11-19 21:52:54 +08:00
|
|
|
// Revision 1.3 1998/11/19 13:52:54 curt
|
|
|
|
// port configuration tweaks & experiments.
|
|
|
|
//
|
1998-11-19 11:35:43 +08:00
|
|
|
// Revision 1.2 1998/11/19 03:35:43 curt
|
|
|
|
// Updates ...
|
|
|
|
//
|
1998-11-16 21:53:01 +08:00
|
|
|
// Revision 1.1 1998/11/16 13:53:02 curt
|
|
|
|
// Initial revision.
|
|
|
|
//
|