]> git.mxchange.org Git - flightgear.git/commitdiff
Revamping I/O system.
authorcurt <curt>
Fri, 19 Nov 1999 02:10:24 +0000 (02:10 +0000)
committercurt <curt>
Fri, 19 Nov 1999 02:10:24 +0000 (02:10 +0000)
22 files changed:
src/Main/Makefile.am
src/Main/fg_init.cxx
src/Main/fg_io.cxx [new file with mode: 0644]
src/Main/fg_io.hxx [new file with mode: 0644]
src/Main/fg_serial.cxx [deleted file]
src/Main/fg_serial.hxx [deleted file]
src/Main/main.cxx
src/Main/options.cxx
src/Main/options.hxx
src/Network/Makefile.am
src/Network/fg_file.cxx [new file with mode: 0644]
src/Network/fg_file.hxx [new file with mode: 0644]
src/Network/fg_serial.cxx [new file with mode: 0644]
src/Network/fg_serial.hxx [new file with mode: 0644]
src/Network/garmin.cxx [new file with mode: 0644]
src/Network/garmin.hxx [new file with mode: 0644]
src/Network/iochannel.cxx [new file with mode: 0644]
src/Network/iochannel.hxx [new file with mode: 0644]
src/Network/nmea.cxx [new file with mode: 0644]
src/Network/nmea.hxx [new file with mode: 0644]
src/Network/protocol.cxx [new file with mode: 0644]
src/Network/protocol.hxx [new file with mode: 0644]

index dec1571d3381d6102ce67f82e2bf7ea1dd80a9e7..4b003869879f12b3489996d204792e8c3da1982b 100644 (file)
@@ -25,13 +25,15 @@ bin_SCRIPTS = runfgfs runfgfs.bat
 
 fgfs_SOURCES = \
        fg_init.cxx fg_init.hxx \
-       fg_serial.cxx fg_serial.hxx \
+       fg_io.cxx fg_io.hxx \
        keyboard.cxx keyboard.hxx \
        main.cxx \
        options.cxx options.hxx \
        splash.cxx splash.hxx \
        views.cxx views.hxx
 
+#      fg_serial.cxx fg_serial.hxx \
+
 fgfs_LDADD = \
        $(top_builddir)/Simulator/Aircraft/libAircraft.a \
        $(top_builddir)/Simulator/Astro/libAstro.a \
@@ -40,7 +42,6 @@ fgfs_LDADD = \
        $(top_builddir)/Simulator/Controls/libControls.a \
        $(top_builddir)/Simulator/FDM/libFlight.a \
        $(top_builddir)/Simulator/FDM/Balloon/libBalloon.a \
-       $(top_builddir)/Simulator/FDM/External/libExternal.a \
        $(top_builddir)/Simulator/FDM/JSBsim/libJSBsim.a \
        $(top_builddir)/Simulator/FDM/LaRCsim/libLaRCsim.a \
        $(top_builddir)/Simulator/GUI/libGUI.a \
@@ -56,7 +57,6 @@ fgfs_LDADD = \
        $(top_builddir)/Lib/Screen/libScreen.a \
        $(top_builddir)/Lib/Math/libMath.a \
        $(top_builddir)/Lib/Bucket/libBucket.a \
-       $(top_builddir)/Lib/Voronoi/libVoronoi.a \
        $(top_builddir)/Lib/Debug/libDebug.a \
        -lpu -lfnt -lssg -lsg \
        $(top_builddir)/Lib/Misc/libMisc.a \
index 542273cdbeab9fa3b71a8825af32e3add7c53124..6aac3191b0b9e58f430003eeaa35425b32c09044 100644 (file)
@@ -57,6 +57,7 @@
 #include <Autopilot/autopilot.hxx>
 #include <Cockpit/cockpit.hxx>
 #include <FDM/Balloon.h>
+#include <FDM/External.hxx>
 #include <FDM/JSBsim.hxx>
 #include <FDM/LaRCsim.hxx>
 #include <FDM/MagicCarpet.hxx>
@@ -82,9 +83,9 @@
 #endif
 
 #include "fg_init.hxx"
+#include "fg_io.hxx"
 #include "options.hxx"
 #include "views.hxx"
-#include "fg_serial.hxx"
 
 #if defined(FX) && defined(XMESA)
 #include <GL/xmesa.h>
@@ -181,7 +182,10 @@ bool fgInitPosition( void ) {
 // General house keeping initializations
 bool fgInitGeneral( void ) {
     string root;
+
+#if defined(FX) && defined(XMESA)
     char *mesa_win_state;
+#endif
 
     FG_LOG( FG_GENERAL, FG_INFO, "General Initialization" );
     FG_LOG( FG_GENERAL, FG_INFO, "======= ==============" );
@@ -238,6 +242,9 @@ bool fgInitSubsystems( void ) {
     } else if ( current_options.get_flight_model() == 
                FGInterface::FG_MAGICCARPET ) {
        cur_fdm_state = new FGMagicCarpet;
+    } else if ( current_options.get_flight_model() == 
+               FGInterface::FG_EXTERNAL ) {
+       cur_fdm_state = new FGExternal;
     } else {
        FG_LOG( FG_GENERAL, FG_ALERT,
                "No flight model, can't init aircraft" );
@@ -499,9 +506,9 @@ bool fgInitSubsystems( void ) {
     // Autopilot init added here, by Jeff Goeke-Smith
     fgAPInit(&current_aircraft);
 
-    // Initialize serial ports
+    // Initialize I/O channels
 #if ! defined( MACOS )
-    fgSerialInit();
+    fgIOInit();
 #endif
 
     FG_LOG( FG_GENERAL, FG_INFO, endl);
diff --git a/src/Main/fg_io.cxx b/src/Main/fg_io.cxx
new file mode 100644 (file)
index 0000000..36a9529
--- /dev/null
@@ -0,0 +1,405 @@
+// fg_io.cxx -- higher level I/O channel management routines
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#include <Include/compiler.h>
+
+// #ifdef FG_HAVE_STD_INCLUDES
+// #  include <cmath>
+// #  include <cstdlib>    // atoi()
+// #else
+// #  include <math.h>
+// #  include <stdlib.h>   // atoi()
+// #endif
+
+#include STL_STRING
+// #include STL_IOSTREAM                                           
+// #include <vector>                                                               
+
+#include <Debug/logstream.hxx>
+// #include <Aircraft/aircraft.hxx>
+// #include <Include/fg_constants.h>
+#include <Include/fg_types.hxx>
+#include <Main/options.hxx>
+
+#include <Network/iochannel.hxx>
+#include <Network/fg_file.hxx>
+#include <Network/fg_serial.hxx>
+
+#include <Network/protocol.hxx>
+#include <Network/garmin.hxx>
+#include <Network/nmea.hxx>
+
+// #include <Time/fg_time.hxx>
+#include <Time/timestamp.hxx>
+
+FG_USING_STD(string);
+
+
+// define the global I/O channel list
+io_container global_io_list;
+
+
+// configure a port based on the config string
+static FGProtocol *parse_port_config( const string& config )
+{
+    string::size_type begin, end;
+
+    begin = 0;
+
+    FG_LOG( FG_IO, FG_INFO, "Parse I/O channel request: " << config );
+
+    // determine protocol
+    end = config.find(",", begin);
+    if ( end == string::npos ) {
+       return NULL;            // dummy
+    }
+    
+    string protocol = config.substr(begin, end - begin);
+    begin = end + 1;
+    FG_LOG( FG_IO, FG_INFO, "  protocol = " << protocol );
+
+    FGProtocol *io;
+    if ( protocol == "nmea" ) {
+       FGNMEA *nmea = new FGNMEA;
+       io = nmea;
+    } else if ( protocol == "garmin" ) {
+       FGGarmin *garmin = new FGGarmin;
+       io = garmin;
+    } else {
+       return NULL;
+    }
+
+    // determine medium
+    end = config.find(",", begin);
+    if ( end == string::npos ) {
+       return NULL;            // dummy
+    }
+    
+    string medium = config.substr(begin, end - begin);
+    begin = end + 1;
+    FG_LOG( FG_IO, FG_INFO, "  medium = " << medium );
+
+    // determine direction
+    end = config.find(",", begin);
+    if ( end == string::npos ) {
+       return NULL;            // dummy
+    }
+    
+    string direction = config.substr(begin, end - begin);
+    begin = end + 1;
+    io->set_direction( direction );
+    FG_LOG( FG_IO, FG_INFO, "  direction = " << direction );
+
+    // determine hertz
+    end = config.find(",", begin);
+    if ( end == string::npos ) {
+       return NULL;            // dummy
+    }
+    
+    string hertz_str = config.substr(begin, end - begin);
+    begin = end + 1;
+    double hertz = atof( hertz_str.c_str() );
+    io->set_hz( hertz );
+    FG_LOG( FG_IO, FG_INFO, "  hertz = " << hertz );
+
+    if ( medium == "serial" ) {
+       FGSerial *ch = new FGSerial;
+       io->set_io_channel( ch );
+
+       // device name
+       end = config.find(",", begin);
+       if ( end == string::npos ) {
+           return NULL;
+       }
+    
+       ch->set_device( config.substr(begin, end - begin) );
+       begin = end + 1;
+       FG_LOG( FG_IO, FG_INFO, "  device = " << ch->get_device() );
+
+       // baud
+       ch->set_baud( config.substr(begin) );
+       FG_LOG( FG_IO, FG_INFO, "  baud = " << ch->get_baud() );
+
+       io->set_io_channel( ch );
+    } else if ( medium == "file" ) {
+       FGFile *ch = new FGFile;
+
+       // file name
+       ch->set_file_name( config.substr(begin) );
+       FG_LOG( FG_IO, FG_INFO, "  file name = " << ch->get_file_name() );
+
+       io->set_io_channel( ch );
+    } else if ( medium == "socket" ) {
+       // ch = new FGSocket;
+    }
+
+    return io;
+}
+
+
+// step through the port config streams (from fgOPTIONS) and setup
+// serial port channels for each
+void fgIOInit() {
+    FGProtocol *p;
+    string_list channel_options_list = 
+       current_options.get_channel_options_list();
+
+    // we could almost do this in a single step except pushing a valid
+    // port onto the port list copies the structure and destroys the
+    // original, which closes the port and frees up the fd ... doh!!!
+
+    // parse the configuration strings and store the results in the
+    // appropriate FGIOChannel structures
+    for ( int i = 0; i < (int)channel_options_list.size(); ++i ) {
+       p = parse_port_config( channel_options_list[i] );
+       if ( p != NULL ) {
+           p->open();
+           global_io_list.push_back( p );
+           if ( !p->is_enabled() ) {
+               FG_LOG( FG_IO, FG_INFO, "I/O Channel config failed." );
+           }
+       } else {
+           FG_LOG( FG_IO, FG_INFO, "I/O Channel parse failed." );
+       }
+    }
+}
+
+
+static void send_fgfs_out( FGIOChannel *p ) {
+}
+
+static void read_fgfs_in( FGIOChannel *p ) {
+}
+
+
+// "RUL" output format (for some sort of motion platform)
+//
+// The Baud rate is 2400 , one start bit, eight data bits, 1 stop bit,
+// no parity.
+//
+// For position it requires a 3-byte data packet defined as follows:
+//
+// First bite: ascII character "P" ( 0x50 or 80 decimal )
+// Second byte X pos. (1-255) 1 being 0* and 255 being 359*
+// Third byte Y pos.( 1-255) 1 being 0* and 255 359*
+//
+// So sending 80 127 127 to the two axis motors will position on 180*
+// The RS- 232 port is a nine pin connector and the only pins used are
+// 3&5.
+
+static void send_rul_out( FGIOChannel *p ) {
+#if 0
+    char rul[256];
+
+    FGInterface *f;
+    FGTime *t;
+
+    f = current_aircraft.fdm_state;
+    t = FGTime::cur_time_params;
+
+    // run as often as possibleonce per second
+
+    // this runs once per second
+    // if ( p->last_time == t->get_cur_time() ) {
+    //    return;
+    // }
+    // p->last_time = t->get_cur_time();
+    // if ( t->get_cur_time() % 2 != 0 ) {
+    //    return;
+    // }
+    
+    // get roll and pitch, convert to degrees
+    double roll_deg = f->get_Phi() * RAD_TO_DEG;
+    while ( roll_deg < -180.0 ) {
+       roll_deg += 360.0;
+    }
+    while ( roll_deg > 180.0 ) {
+       roll_deg -= 360.0;
+    }
+
+    double pitch_deg = f->get_Theta() * RAD_TO_DEG;
+    while ( pitch_deg < -180.0 ) {
+       pitch_deg += 360.0;
+    }
+    while ( pitch_deg > 180.0 ) {
+       pitch_deg -= 360.0;
+    }
+
+    // scale roll and pitch to output format (1 - 255)
+    // straight && level == (128, 128)
+
+    int roll = (int)( (roll_deg+180.0) * 255.0 / 360.0) + 1;
+    int pitch = (int)( (pitch_deg+180.0) * 255.0 / 360.0) + 1;
+
+    sprintf( rul, "p%c%c\n", roll, pitch);
+
+    FG_LOG( FG_IO, FG_INFO, "p " << roll << " " << pitch );
+
+    string rul_sentence = rul;
+    p->port.write_port(rul_sentence);
+#endif
+}
+
+
+// "PVE" (ProVision Entertainment) output format (for some sort of
+// motion platform)
+//
+// Outputs a 5-byte data packet defined as follows:
+//
+// First bite:  ASCII character "P" ( 0x50 or 80 decimal )
+// Second byte:  "roll" value (1-255) 1 being 0* and 255 being 359*
+// Third byte:  "pitch" value (1-255) 1 being 0* and 255 being 359*
+// Fourth byte:  "heave" value (or vertical acceleration?)
+//
+// So sending 80 127 127 to the two axis motors will position on 180*
+// The RS- 232 port is a nine pin connector and the only pins used are
+// 3&5.
+
+static void send_pve_out( FGIOChannel *p ) {
+#if 0
+    char pve[256];
+
+    FGInterface *f;
+    FGTime *t;
+
+
+    f = current_aircraft.fdm_state;
+    t = FGTime::cur_time_params;
+
+    // run as often as possibleonce per second
+
+    // this runs once per second
+    // if ( p->last_time == t->get_cur_time() ) {
+    //    return;
+    // }
+    // p->last_time = t->get_cur_time();
+    // if ( t->get_cur_time() % 2 != 0 ) {
+    //    return;
+    // }
+    
+    // get roll and pitch, convert to degrees
+    double roll_deg = f->get_Phi() * RAD_TO_DEG;
+    while ( roll_deg <= -180.0 ) {
+       roll_deg += 360.0;
+    }
+    while ( roll_deg > 180.0 ) {
+       roll_deg -= 360.0;
+    }
+
+    double pitch_deg = f->get_Theta() * RAD_TO_DEG;
+    while ( pitch_deg <= -180.0 ) {
+       pitch_deg += 360.0;
+    }
+    while ( pitch_deg > 180.0 ) {
+       pitch_deg -= 360.0;
+    }
+
+    short int heave = (int)(f->get_W_body() * 128.0);
+
+    // scale roll and pitch to output format (1 - 255)
+    // straight && level == (128, 128)
+
+    short int roll = (int)(roll_deg * 32768 / 180.0);
+    short int pitch = (int)(pitch_deg * 32768 / 180.0);
+
+    unsigned char roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2;
+    roll_b1 = roll >> 8;
+    roll_b2 = roll & 0x00ff;
+    pitch_b1 = pitch >> 8;
+    pitch_b2 = pitch & 0x00ff;
+    heave_b1 = heave >> 8;
+    heave_b2 = heave & 0x00ff;
+
+    sprintf( pve, "p%c%c%c%c%c%c\n", 
+            roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2 );
+
+    // printf( "p [ %u %u ]  [ %u %u ]  [ %u %u ]\n", 
+    //         roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2 );
+
+    FG_LOG( FG_IO, FG_INFO, "roll=" << roll << " pitch=" << pitch <<
+           " heave=" << heave );
+
+    string pve_sentence = pve;
+    p->port.write_port(pve_sentence);
+#endif
+}
+
+
+// one more level of indirection ...
+static void process_port( FGIOChannel *p ) {
+#if 0
+    if ( p->kind == fgIOCHANNEL::FG_SERIAL_NMEA_OUT ) {
+       send_nmea_out(p);
+    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_NMEA_IN ) {
+       read_nmea_in(p);
+    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_GARMIN_OUT ) {
+       send_garmin_out(p);
+    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_GARMIN_IN ) {
+       read_garmin_in(p);
+    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_FGFS_OUT ) {
+       send_fgfs_out(p);
+    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_FGFS_IN ) {
+       read_fgfs_in(p);
+    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_RUL_OUT ) {
+       send_rul_out(p);
+    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_PVE_OUT ) {
+       send_pve_out(p);
+    }
+#endif
+}
+
+
+// process any serial port work
+void fgIOProcess() {
+    FGProtocol *p;
+
+    // cout << "processing I/O channels" << endl;
+
+    static int inited = 0;
+    int interval;
+    static FGTimeStamp last;
+    FGTimeStamp current;
+
+    if ( ! inited ) {
+       inited = 1;
+       last.stamp();
+       interval = 0;
+    } else {
+        current.stamp();
+       interval = current - last;
+       last = current;
+    }
+
+    for ( int i = 0; i < (int)global_io_list.size(); ++i ) {
+       // cout << "  channel = " << i << endl;
+       p = global_io_list[i];
+
+       if ( p->is_enabled() ) {
+           p->dec_count_down( interval );
+           if ( p->get_count_down() < 0 ) {
+               p->process();
+               p->set_count_down( 1000000.0 / p->get_hz() );
+           }
+       }
+    }
+}
diff --git a/src/Main/fg_io.hxx b/src/Main/fg_io.hxx
new file mode 100644 (file)
index 0000000..163d96f
--- /dev/null
@@ -0,0 +1,51 @@
+// fg_io.hxx -- Higher level I/O managment routines
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#ifndef _FG_IO_HXX
+#define _FG_IO_HXX
+
+
+#include "Include/compiler.h"
+
+// #include <string>
+
+// #ifdef FG_HAVE_STD_INCLUDES
+// #  include <ctime>
+// #else
+// #  include <time.h>
+// #endif
+
+#include <Network/iochannel.hxx>
+
+
+// initialize I/O channels based on command line options (if any)
+void fgIOInit();
+
+
+// process any I/O work
+void fgIOProcess();
+
+
+#endif // _FG_IO_HXX
+
+
diff --git a/src/Main/fg_serial.cxx b/src/Main/fg_serial.cxx
deleted file mode 100644 (file)
index 211076f..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-// fg_serial.cxx -- higher level serial port management routines
-//
-// 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$
-
-
-#include <Include/compiler.h>
-
-#ifdef FG_HAVE_STD_INCLUDES
-#  include <cmath>
-#  include <cstdlib>    // atoi()
-#else
-#  include <math.h>
-#  include <stdlib.h>   // atoi()
-#endif
-
-#include STL_STRING
-#include STL_IOSTREAM                                           
-#include <vector>                                                               
-
-#include <Debug/logstream.hxx>
-#include <Aircraft/aircraft.hxx>
-#include <Include/fg_constants.h>
-#include <Serial/serial.hxx>
-#include <Time/fg_time.hxx>
-
-#include "options.hxx"
-
-#include "fg_serial.hxx"
-
-FG_USING_STD(string);
-FG_USING_STD(vector);
-
-// support an arbitrary number of serial channels.  Each channel can
-// be assigned to an arbitrary port.  Bi-directional communication is
-// supported by the underlying layer, but probably will never be
-// needed by FGFS?
-
-typedef vector < fgIOCHANNEL > io_container;
-typedef io_container::iterator io_iterator;
-typedef io_container::const_iterator const_io_iterator;
-
-// define the four channels
-io_container port_list;
-
-
-fgIOCHANNEL::fgIOCHANNEL() :
-    kind( FG_SERIAL_DISABLED ),
-    valid_config( false )
-{
-}
-
-
-fgIOCHANNEL::~fgIOCHANNEL() {
-}
-
-
-// configure a port based on the config string
-static fgIOCHANNEL parse_port_config( const string& config )
-{
-    fgIOCHANNEL p;
-
-    string::size_type begin, end;
-
-    begin = 0;
-
-    FG_LOG( FG_SERIAL, FG_INFO, "Parse serial port config: " << config );
-
-    // device name
-    end = config.find(",", begin);
-    if ( end == string::npos ) {
-       return p;
-    }
-    
-    p.device = config.substr(begin, end - begin);
-    begin = end + 1;
-    FG_LOG( FG_SERIAL, FG_INFO, "  device = " << p.device );
-
-    // format
-    end = config.find(",", begin);
-    if ( end == string::npos ) {
-       return p;
-    }
-    
-    p.format = config.substr(begin, end - begin);
-    begin = end + 1;
-    FG_LOG( FG_SERIAL, FG_INFO, "  format = " << p.format );
-
-    // baud
-    end = config.find(",", begin);
-    if ( end == string::npos ) {
-       return p;
-    }
-    
-    p.baud = config.substr(begin, end - begin);
-    begin = end + 1;
-    FG_LOG( FG_SERIAL, FG_INFO, "  baud = " << p.baud );
-
-    // direction
-    p.direction = config.substr(begin);
-    FG_LOG( FG_SERIAL, FG_INFO, "  direction = " << p.direction );
-
-    p.valid_config = true;
-
-    return p;
-}
-
-
-// configure a port based on the config info
-static bool config_port( fgIOCHANNEL &p )
-{
-    if ( p.port.is_enabled() ) {
-       FG_LOG( FG_SERIAL, FG_ALERT, "This shouldn't happen, but the port " 
-               << "is already in use, ignoring" );
-       return false;
-    }
-
-    if ( ! p.port.open_port( p.device ) ) {
-       FG_LOG( FG_SERIAL, FG_ALERT, "Error opening device: " << p.device );
-       return false;
-    }
-
-    // cout << "fd = " << p.port.fd << endl;
-
-    if ( ! p.port.set_baud( atoi( p.baud.c_str() ) ) ) {
-       FG_LOG( FG_SERIAL, FG_ALERT, "Error setting baud: " << p.baud );
-       return false;
-    }
-
-    if ( p.format == "nmea" ) {
-       if ( p.direction == "out" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_NMEA_OUT;
-       } else if ( p.direction == "in" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_NMEA_IN;
-       } else {
-           FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
-           return false;
-       }
-    } else if ( p.format == "garmin" ) {
-       if ( p.direction == "out" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_GARMIN_OUT;
-       } else if ( p.direction == "in" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_GARMIN_IN;
-       } else {
-           FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
-           return false;
-       }
-    } else if ( p.format == "fgfs" ) {
-       if ( p.direction == "out" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_FGFS_OUT;
-       } else if ( p.direction == "in" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_FGFS_IN;
-       } else {
-           FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
-           return false;
-       }
-    } else if ( p.format == "rul" ) {
-       if ( p.direction == "out" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_RUL_OUT;
-       } else if ( p.direction == "in" ) {
-           FG_LOG( FG_SERIAL, FG_ALERT, "RUL format is outgoing only" );
-           return false;
-       } else {
-           FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
-           return false;
-       }
-    } else if ( p.format == "pve" ) {
-       if ( p.direction == "out" ) {
-           p.kind = fgIOCHANNEL::FG_SERIAL_PVE_OUT;
-       } else if ( p.direction == "in" ) {
-           FG_LOG( FG_SERIAL, FG_ALERT, 
-                   "ProVision Entertainment format is outgoing only" );
-           return false;
-       } else {
-           FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
-           return false;
-       }
-    } else {
-       FG_LOG( FG_SERIAL, FG_ALERT, "Unknown format" );
-       return false;
-    }
-
-    return true;
-}
-
-
-// step through the port config streams (from fgOPTIONS) and setup
-// serial port channels for each
-void fgSerialInit() {
-    fgIOCHANNEL port;
-    bool result;
-    str_container port_options_list = current_options.get_port_options_list();
-
-    // we could almost do this in a single step except pushing a valid
-    // port onto the port list copies the structure and destroys the
-    // original, which closes the port and frees up the fd ... doh!!!
-
-    // parse the configuration strings and store the results in stub
-    // fgIOCHANNEL structures
-    const_str_iterator current_str = port_options_list.begin();
-    const_str_iterator last_str = port_options_list.end();
-    for ( ; current_str != last_str; ++current_str ) {
-       port = parse_port_config( *current_str );
-       if ( port.valid_config ) {
-           result = config_port( port );
-           if ( result ) {
-               port_list.push_back( port );
-           }
-       }
-    }
-}
-
-
-char calc_nmea_cksum(char *sentence) {
-    unsigned char sum = 0;
-    int i, len;
-
-    // printf("%s\n", sentence);
-
-    len = strlen(sentence);
-    sum = sentence[0];
-    for ( i = 1; i < len; i++ ) {
-        // printf("%c", sentence[i]);
-        sum ^= sentence[i];
-    }
-    // printf("\n");
-
-    // printf("sum = %02x\n", sum);
-    return sum;
-}
-
-
-static void send_nmea_out( fgIOCHANNEL *p ) {
-    char rmc[256], gga[256];
-    char rmc_sum[10], gga_sum[10];
-    char dir;
-    int deg;
-    double min;
-    FGInterface *f;
-    FGTime *t;
-
-    f = current_aircraft.fdm_state;
-    t = FGTime::cur_time_params;
-
-    // run once every two seconds
-    if ( p->last_time == t->get_cur_time() ) {
-       return;
-    }
-    p->last_time = t->get_cur_time();
-    if ( t->get_cur_time() % 2 != 0 ) {
-       return;
-    }
-
-    char utc[10];
-    sprintf( utc, "%02d%02d%02d", 
-            t->getGmt()->tm_hour, t->getGmt()->tm_min, t->getGmt()->tm_sec );
-
-    char lat[20];
-    double latd = f->get_Latitude() * RAD_TO_DEG;
-    if ( latd < 0.0 ) {
-       latd *= -1.0;
-       dir = 'S';
-    } else {
-       dir = 'N';
-    }
-    deg = (int)(latd);
-    min = (latd - (double)deg) * 60.0;
-    sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
-
-    char lon[20];
-    double lond = f->get_Longitude() * RAD_TO_DEG;
-    if ( lond < 0.0 ) {
-       lond *= -1.0;
-       dir = 'W';
-    } else {
-       dir = 'E';
-    }
-    deg = (int)(lond);
-    min = (lond - (double)deg) * 60.0;
-    sprintf( lon, "%03d%06.3f,%c", abs(deg), min, dir);
-
-    char speed[10];
-    sprintf( speed, "%05.1f", f->get_V_equiv_kts() );
-
-    char heading[10];
-    sprintf( heading, "%05.1f", f->get_Psi() * RAD_TO_DEG );
-
-    char altitude_m[10];
-    sprintf( altitude_m, "%02d", (int)(f->get_Altitude() * FEET_TO_METER) );
-
-    char altitude_ft[10];
-    sprintf( altitude_ft, "%02d", (int)f->get_Altitude() );
-
-    char date[10];
-    sprintf( date, "%02d%02d%02d", t->getGmt()->tm_mday, 
-            t->getGmt()->tm_mon+1, t->getGmt()->tm_year );
-
-    // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
-    sprintf( rmc, "GPRMC,%s,A,%s,%s,%s,%s,%s,0.000,E",
-            utc, lat, lon, speed, heading, date );
-    sprintf( rmc_sum, "%02X", calc_nmea_cksum(rmc) );
-
-    sprintf( gga, "GPGGA,%s,%s,%s,1,,,%s,F,,,,",
-            utc, lat, lon, altitude_ft );
-    sprintf( gga_sum, "%02X", calc_nmea_cksum(gga) );
-
-
-    FG_LOG( FG_SERIAL, FG_DEBUG, rmc );
-    FG_LOG( FG_SERIAL, FG_DEBUG, gga );
-
-    // RMC sentence
-    string rmc_sentence = "$";
-    rmc_sentence += rmc;
-    rmc_sentence += "*";
-    rmc_sentence += rmc_sum;
-    rmc_sentence += "\n";
-    p->port.write_port(rmc_sentence);
-    // cout << rmc_sentence;
-
-    // GGA sentence
-    string gga_sentence = "$";
-    gga_sentence += gga;
-    gga_sentence += "*";
-    gga_sentence += gga_sum;
-    gga_sentence += "\n";
-    p->port.write_port(gga_sentence);
-    // cout << gga_sentence;
-}
-
-static void read_nmea_in( fgIOCHANNEL *p ) {
-}
-
-static void send_garmin_out( fgIOCHANNEL *p ) {
-    char rmc[256], rmc_sum[256], rmz[256], rmz_sum[256];
-    char dir;
-    int deg;
-    double min;
-    FGInterface *f;
-    FGTime *t;
-
-    f = current_aircraft.fdm_state;
-    t = FGTime::cur_time_params;
-
-    // run once per second
-    if ( p->last_time == t->get_cur_time() ) {
-       return;
-    }
-    p->last_time = t->get_cur_time();
-    if ( t->get_cur_time() % 2 != 0 ) {
-       return;
-    }
-    
-    char utc[10];
-    sprintf( utc, "%02d%02d%02d", 
-            t->getGmt()->tm_hour, t->getGmt()->tm_min, t->getGmt()->tm_sec );
-
-    char lat[20];
-    double latd = f->get_Latitude() * RAD_TO_DEG;
-    if ( latd < 0.0 ) {
-       latd *= -1.0;
-       dir = 'S';
-    } else {
-       dir = 'N';
-    }
-    deg = (int)(latd);
-    min = (latd - (double)deg) * 60.0;
-    sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
-
-    char lon[20];
-    double lond = f->get_Longitude() * RAD_TO_DEG;
-    if ( lond < 0.0 ) {
-       lond *= -1.0;
-       dir = 'W';
-    } else {
-       dir = 'E';
-    }
-    deg = (int)(lond);
-    min = (lond - (double)deg) * 60.0;
-    sprintf( lon, "%03d%06.3f,%c", abs(deg), min, dir);
-
-    char speed[10];
-    sprintf( speed, "%05.1f", f->get_V_equiv_kts() );
-
-    char heading[10];
-    sprintf( heading, "%05.1f", f->get_Psi() * RAD_TO_DEG );
-
-    char altitude_m[10];
-    sprintf( altitude_m, "%02d", (int)(f->get_Altitude() * FEET_TO_METER) );
-
-    char altitude_ft[10];
-    sprintf( altitude_ft, "%02d", (int)f->get_Altitude() );
-
-    char date[10];
-    sprintf( date, "%02d%02d%02d", t->getGmt()->tm_mday, 
-            t->getGmt()->tm_mon+1, t->getGmt()->tm_year );
-
-    // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
-    sprintf( rmc, "GPRMC,%s,A,%s,%s,%s,%s,%s,000.0,E",
-            utc, lat, lon, speed, heading, date );
-    sprintf( rmc_sum, "%02X", calc_nmea_cksum(rmc) );
-
-    // sprintf( gga, "$GPGGA,%s,%s,%s,1,04,0.0,%s,M,00.0,M,,*00\r\n",
-    //          utc, lat, lon, altitude_m );
-
-    sprintf( rmz, "PGRMZ,%s,f,3", altitude_ft );
-    sprintf( rmz_sum, "%02X", calc_nmea_cksum(rmz) );
-
-    FG_LOG( FG_SERIAL, FG_DEBUG, rmc );
-    FG_LOG( FG_SERIAL, FG_DEBUG, rmz );
-
-    // RMC sentence
-    string rmc_sentence = "$";
-    rmc_sentence += rmc;
-    rmc_sentence += "*";
-    rmc_sentence += rmc_sum;
-    rmc_sentence += "\n";
-    p->port.write_port(rmc_sentence);
-    // cout << rmc_sentence;
-
-    // RMZ sentence (garmin proprietary)
-    string rmz_sentence = "$";
-    rmz_sentence += rmz;
-    rmz_sentence += "*";
-    rmz_sentence += rmz_sum;
-    rmz_sentence += "\n";
-    p->port.write_port(rmz_sentence);
-    // cout << rmz_sentence;
-}
-
-static void read_garmin_in( fgIOCHANNEL *p ) {
-}
-
-static void send_fgfs_out( fgIOCHANNEL *p ) {
-}
-
-static void read_fgfs_in( fgIOCHANNEL *p ) {
-}
-
-
-// "RUL" output format (for some sort of motion platform)
-//
-// The Baud rate is 2400 , one start bit, eight data bits, 1 stop bit,
-// no parity.
-//
-// For position it requires a 3-byte data packet defined as follows:
-//
-// First bite: ascII character "P" ( 0x50 or 80 decimal )
-// Second byte X pos. (1-255) 1 being 0* and 255 being 359*
-// Third byte Y pos.( 1-255) 1 being 0* and 255 359*
-//
-// So sending 80 127 127 to the two axis motors will position on 180*
-// The RS- 232 port is a nine pin connector and the only pins used are
-// 3&5.
-
-static void send_rul_out( fgIOCHANNEL *p ) {
-    char rul[256];
-
-    FGInterface *f;
-    FGTime *t;
-
-    f = current_aircraft.fdm_state;
-    t = FGTime::cur_time_params;
-
-    // run as often as possibleonce per second
-
-    // this runs once per second
-    // if ( p->last_time == t->get_cur_time() ) {
-    //    return;
-    // }
-    // p->last_time = t->get_cur_time();
-    // if ( t->get_cur_time() % 2 != 0 ) {
-    //    return;
-    // }
-    
-    // get roll and pitch, convert to degrees
-    double roll_deg = f->get_Phi() * RAD_TO_DEG;
-    while ( roll_deg < -180.0 ) {
-       roll_deg += 360.0;
-    }
-    while ( roll_deg > 180.0 ) {
-       roll_deg -= 360.0;
-    }
-
-    double pitch_deg = f->get_Theta() * RAD_TO_DEG;
-    while ( pitch_deg < -180.0 ) {
-       pitch_deg += 360.0;
-    }
-    while ( pitch_deg > 180.0 ) {
-       pitch_deg -= 360.0;
-    }
-
-    // scale roll and pitch to output format (1 - 255)
-    // straight && level == (128, 128)
-
-    int roll = (int)( (roll_deg+180.0) * 255.0 / 360.0) + 1;
-    int pitch = (int)( (pitch_deg+180.0) * 255.0 / 360.0) + 1;
-
-    sprintf( rul, "p%c%c\n", roll, pitch);
-
-    FG_LOG( FG_SERIAL, FG_INFO, "p " << roll << " " << pitch );
-
-    string rul_sentence = rul;
-    p->port.write_port(rul_sentence);
-}
-
-
-// "PVE" (ProVision Entertainment) output format (for some sort of
-// motion platform)
-//
-// Outputs a 5-byte data packet defined as follows:
-//
-// First bite:  ASCII character "P" ( 0x50 or 80 decimal )
-// Second byte:  "roll" value (1-255) 1 being 0* and 255 being 359*
-// Third byte:  "pitch" value (1-255) 1 being 0* and 255 being 359*
-// Fourth byte:  "heave" value (or vertical acceleration?)
-//
-// So sending 80 127 127 to the two axis motors will position on 180*
-// The RS- 232 port is a nine pin connector and the only pins used are
-// 3&5.
-
-static void send_pve_out( fgIOCHANNEL *p ) {
-    char pve[256];
-
-    FGInterface *f;
-    FGTime *t;
-
-
-    f = current_aircraft.fdm_state;
-    t = FGTime::cur_time_params;
-
-    // run as often as possibleonce per second
-
-    // this runs once per second
-    // if ( p->last_time == t->get_cur_time() ) {
-    //    return;
-    // }
-    // p->last_time = t->get_cur_time();
-    // if ( t->get_cur_time() % 2 != 0 ) {
-    //    return;
-    // }
-    
-    // get roll and pitch, convert to degrees
-    double roll_deg = f->get_Phi() * RAD_TO_DEG;
-    while ( roll_deg <= -180.0 ) {
-       roll_deg += 360.0;
-    }
-    while ( roll_deg > 180.0 ) {
-       roll_deg -= 360.0;
-    }
-
-    double pitch_deg = f->get_Theta() * RAD_TO_DEG;
-    while ( pitch_deg <= -180.0 ) {
-       pitch_deg += 360.0;
-    }
-    while ( pitch_deg > 180.0 ) {
-       pitch_deg -= 360.0;
-    }
-
-    short int heave = (int)(f->get_W_body() * 128.0);
-
-    // scale roll and pitch to output format (1 - 255)
-    // straight && level == (128, 128)
-
-    short int roll = (int)(roll_deg * 32768 / 180.0);
-    short int pitch = (int)(pitch_deg * 32768 / 180.0);
-
-    unsigned char roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2;
-    roll_b1 = roll >> 8;
-    roll_b2 = roll & 0x00ff;
-    pitch_b1 = pitch >> 8;
-    pitch_b2 = pitch & 0x00ff;
-    heave_b1 = heave >> 8;
-    heave_b2 = heave & 0x00ff;
-
-    sprintf( pve, "p%c%c%c%c%c%c\n", 
-            roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2 );
-
-    // printf( "p [ %u %u ]  [ %u %u ]  [ %u %u ]\n", 
-    //         roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2 );
-
-    FG_LOG( FG_SERIAL, FG_INFO, "roll=" << roll << " pitch=" << pitch <<
-           " heave=" << heave );
-
-    string pve_sentence = pve;
-    p->port.write_port(pve_sentence);
-}
-
-
-// one more level of indirection ...
-static void process_port( fgIOCHANNEL *p ) {
-    if ( p->kind == fgIOCHANNEL::FG_SERIAL_NMEA_OUT ) {
-       send_nmea_out(p);
-    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_NMEA_IN ) {
-       read_nmea_in(p);
-    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_GARMIN_OUT ) {
-       send_garmin_out(p);
-    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_GARMIN_IN ) {
-       read_garmin_in(p);
-    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_FGFS_OUT ) {
-       send_fgfs_out(p);
-    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_FGFS_IN ) {
-       read_fgfs_in(p);
-    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_RUL_OUT ) {
-       send_rul_out(p);
-    } else if ( p->kind == fgIOCHANNEL::FG_SERIAL_PVE_OUT ) {
-       send_pve_out(p);
-    }
-}
-
-
-// process any serial port work
-void fgSerialProcess() {
-    fgIOCHANNEL *port;
-    
-    io_iterator current = port_list.begin();
-    io_iterator last = port_list.end();
-
-    for ( ; current != last; ++current ) {
-       port = current;
-       if ( port->kind != fgIOCHANNEL::FG_SERIAL_DISABLED ) {
-           process_port ( port );
-       }
-    }
-}
diff --git a/src/Main/fg_serial.hxx b/src/Main/fg_serial.hxx
deleted file mode 100644 (file)
index 006c6bd..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-// fg_serial.hxx -- Higher level serial port managment routines
-//
-// 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$
-
-
-#ifndef _FG_SERIAL_HXX
-#define _FG_SERIAL_HXX
-
-
-#ifndef __cplusplus
-# error This library requires C++
-#endif
-
-#include "Include/compiler.h"
-
-#include <string>
-
-#ifdef FG_HAVE_STD_INCLUDES
-#  include <ctime>
-#else
-#  include <time.h>
-#endif
-
-#include <Serial/serial.hxx>
-
-
-class fgIOCHANNEL {
-
-public:
-
-    // Types of serial port protocols
-    enum fgPortKind {
-       FG_SERIAL_DISABLED = 0,
-       FG_SERIAL_NMEA_OUT = 1,
-       FG_SERIAL_NMEA_IN = 2,
-       FG_SERIAL_GARMIN_OUT = 3,
-       FG_SERIAL_GARMIN_IN = 4,
-       FG_SERIAL_FGFS_OUT = 5,
-       FG_SERIAL_FGFS_IN = 6,
-
-       FG_SERIAL_RUL_OUT = 7,  // Raul E Horcasitas <rul@compuserve.com>
-       FG_SERIAL_PVE_OUT = 8   // "Jeff Vrachan" 
-                               // <jeffv@provisionentertainment.com>
-    };
-
-    string device;
-    string format;
-    string baud;
-    string direction;
-
-    fgPortKind kind;
-    fgSERIAL port;
-    time_t last_time;
-    bool valid_config;
-
-    fgIOCHANNEL();
-    ~fgIOCHANNEL();
-};
-
-
-// support up to four serial channels.  Each channel can be assigned
-// to an arbitrary port.  Bi-directional communication is supported by
-// the underlying layer.
-
-// define the four channels
-// extern fgIOCHANNEL port_a;
-// extern fgIOCHANNEL port_b;
-// extern fgIOCHANNEL port_c;
-// extern fgIOCHANNEL port_d;
-
-
-// initialize serial ports based on command line options (if any)
-void fgSerialInit();
-
-
-// process any serial port work
-void fgSerialProcess();
-
-
-#endif // _FG_SERIAL_HXX
-
-
index 3426accc4cf5347393f84b9c9b1f8fd87bc8cc92..16ff2b189346db04794bf5d55ccf857836cb4daf 100644 (file)
 #endif
 
 #include "fg_init.hxx"
+#include "fg_io.hxx"
 #include "keyboard.hxx"
 #include "options.hxx"
 #include "splash.hxx"
 #include "views.hxx"
-#include "fg_serial.hxx"
 
 
 // -dw- use custom sioux settings so I can see output window
@@ -812,8 +812,8 @@ static void fgMainLoop( void ) {
     }
 
 #if ! defined( MACOS )
-    // Do any serial port work that might need to be done
-    fgSerialProcess();
+    // Do any I/O channel work that might need to be done
+    fgIOProcess();
 #endif
 
     // see if we need to load any new scenery tiles
index eb10053b86fdc189767b1e7f54dd3765c1208091..7b783e78393ced32b3dbda33de72324eac2e69cb 100644 (file)
@@ -50,7 +50,6 @@ bool global_fullscreen = true;
 #include <Time/fg_time.hxx>
 
 #include "options.hxx"
-#include "fg_serial.hxx"
 
 FG_USING_STD(string);
 FG_USING_NAMESPACE(std);
@@ -215,8 +214,7 @@ fgOPTIONS::fgOPTIONS() :
     net_id = "Johnney";                // default pilot's name
 
     // initialize port config string list
-    port_options_list.erase ( port_options_list.begin(), 
-                             port_options_list.end() );
+    channel_options_list.clear();
 }
 
 void 
@@ -533,31 +531,35 @@ fgOPTIONS::parse_fov( const string& arg ) {
 }
 
 
-// Parse serial port option --serial=/dev/ttyS1,nmea,4800,out
+// Parse I/O channel option
 //
-// Format is "--serial=device,format,baud,direction" where
+// Format is "--protocol=medium,direction,hz,medium_options,..."
+//
+//   protocol = { nmea, garmin, fgfs, rul, pve, etc. }
+//   medium = { serial, socket, file, etc. }
+//   direction = { in, out, bi }
+//   hz = number of times to process channel per second (floating
+//        point values are ok.
+//
+// Serial example "--nmea=serial,dir,hz,device,baud" where
 // 
-//  device = OS device name to be open()'ed
-//  format = {nmea, garmin,fgfs,rul,pve}
+//  device = OS device name of serial line to be open()'ed
 //  baud = {300, 1200, 2400, ..., 230400}
-//  direction = {in, out, bi}
+//
+// Socket exacmple "--fgfs=socket,dir,hz,machine,port" where
+// 
+//  machine = machine name or ip address if client, leave empty if server
+//  port = port, leave empty to let system choose
+//
+// File example "--garmin=file,dir,hz,filename" where
+// 
+//  filename = file system file name
 
 bool 
-fgOPTIONS::parse_serial( const string& serial_str ) {
-    string::size_type pos;
-
-    // cout << "Serial string = " << serial_str << endl;
-
-    // a flailing attempt to see if the port config string has a
-    // chance at being valid
-    pos = serial_str.find(",");
-    if ( pos == string::npos ) {
-       FG_LOG( FG_GENERAL, FG_ALERT, 
-               "Malformed serial port configure string" );
-       return false;
-    }
-    
-    port_options_list.push_back( serial_str );
+fgOPTIONS::parse_channel( const string& type, const string& channel_str ) {
+    // cout << "Channel string = " << channel_str << endl;
+
+    channel_options_list.push_back( type + "," + channel_str );
 
     return true;
 }
@@ -744,8 +746,12 @@ int fgOPTIONS::parse_option( const string& arg ) {
        tris_or_culled = 0;     
     } else if ( arg == "--hud-culled" ) {
        tris_or_culled = 1;
-    } else if ( arg.find( "--serial=" ) != string::npos ) {
-       parse_serial( arg.substr(9) );
+    } else if ( arg.find( "--fgfs=" ) != string::npos ) {
+       parse_channel( "fgfs", arg.substr(7) );
+    } else if ( arg.find( "--garmin=" ) != string::npos ) {
+       parse_channel( "garmin", arg.substr(9) );
+    } else if ( arg.find( "--nmea=" ) != string::npos ) {
+       parse_channel( "nmea", arg.substr(7) );
 #ifdef FG_NETWORK_OLK
     } else if ( arg == "--net-hud" ) {
        net_hud_display = 1;    
index 939c27e2a95091001a08869bcea2e50ecfd23170..ef43963bb27ca9300a62e699a8d2c74ab3e182bd 100644 (file)
 extern bool global_fullscreen;
 #endif
 
+#include <Include/fg_types.hxx>
+
 #include STL_STRING
 #include <vector>
 
 FG_USING_STD(vector);
 FG_USING_STD(string);
 
-typedef vector < string > str_container;
-typedef str_container::iterator str_iterator;
-typedef str_container::const_iterator const_str_iterator;
-
-
 class fgOPTIONS {
 
 public:
@@ -189,14 +186,8 @@ private:
     int time_offset_type;      // Will be set to one of the FG_TIME_* enums,
                                // To deterine how time_offset should be used 
 
-    // Serial Ports, we currently support up to four channels
-    // fgSerialPortKind port_a_kind;  // Port a kind
-    // fgSerialPortKind port_b_kind;  // Port b kind
-    // fgSerialPortKind port_c_kind;  // Port c kind
-    // fgSerialPortKind port_d_kind;  // Port d kind
-
     // Serial port configuration strings
-    str_container port_options_list;
+    string_list channel_options_list;
 
     // Network options
     string net_id;
@@ -272,8 +263,8 @@ public:
     inline int get_time_offset() const { return time_offset; }
     inline int get_time_offset_type() const { return time_offset_type; };
 
-    inline str_container get_port_options_list() const { 
-       return port_options_list;
+    inline string_list get_channel_options_list() const { 
+       return channel_options_list;
     }
     inline string get_net_id() const { return net_id; }
 
@@ -318,7 +309,7 @@ private:
     int parse_tile_radius( const string& arg );
     int parse_fdm( const string& fm );
     double parse_fov( const string& arg );
-    bool parse_serial( const string& serial_str );
+    bool parse_channel( const string& type, const string& channel_str );
 };
 
 
index d8f2ddf15e7b5af88133fe87d2fde89a3f94e79f..9207bdf531876396d4f9ef23cf8e13d86b1175b8 100644 (file)
@@ -1,5 +1,12 @@
 noinst_LIBRARIES = libNetwork.a
 
-libNetwork_a_SOURCES = net_hud.cxx network.cxx network.h
+libNetwork_a_SOURCES = \
+       iochannel.cxx iochannel.hxx \
+       fg_file.cxx fg_file.hxx \
+       fg_serial.cxx fg_serial.hxx \
+       protocol.cxx protocol.hxx \
+       garmin.cxx garmin.hxx \
+       nmea.cxx nmea.hxx \
+       net_hud.cxx network.cxx network.h
 
 INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Simulator
diff --git a/src/Network/fg_file.cxx b/src/Network/fg_file.cxx
new file mode 100644 (file)
index 0000000..748e572
--- /dev/null
@@ -0,0 +1,111 @@
+// fg_file.cxx -- File I/O routines
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#include <Include/compiler.h>
+
+#include STL_STRING
+
+#include <Debug/logstream.hxx>
+#include <Time/fg_time.hxx>
+
+#include "fg_file.hxx"
+
+FG_USING_STD(string);
+
+
+FGFile::FGFile() {
+}
+
+
+FGFile::~FGFile() {
+}
+
+
+// open the file based on specified direction
+bool FGFile::open( FGProtocol::fgProtocolDir dir ) {
+    if ( dir == FGProtocol::out ) {
+       fp = std::open( file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
+                       S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 
+                       S_IROTH | S_IWOTH );
+    } else if ( dir == FGProtocol::in ) {
+       fp = std::open( file_name.c_str(), O_RDONLY );
+    } else {
+       FG_LOG( FG_IO, FG_ALERT, 
+               "Error:  bidirection mode not available for files." );
+       return false;
+    }
+
+    if ( fp == -1 ) {
+       FG_LOG( FG_IO, FG_ALERT, "Error opening file: " << file_name );
+       return false;
+    }
+
+    return true;
+}
+
+
+// read data from file
+bool FGFile::read( char *buf, int *length ) {
+    // save our current position
+    int pos = lseek( fp, 0, SEEK_CUR );
+
+    // read a chunk
+    int result = std::read( fp, buf, FG_MAX_MSG_SIZE );
+
+    // find the end of line and reset position
+    int i;
+    for ( i = 0; i < result && buf[i] != '\n'; ++i );
+    if ( buf[i] == '\n' ) {
+       *length = i + 1;
+    } else {
+       *length = i;
+    }
+    lseek( fp, pos + *length, SEEK_SET );
+    
+    // just in case ...
+    buf[ *length ] = '\0';
+
+    return true;
+}
+
+
+// write data to a file
+bool FGFile::write( char *buf, int length ) {
+    int result = std::write( fp, buf, length );
+    if ( result != length ) {
+       FG_LOG( FG_IO, FG_ALERT, "Error writing data: " << file_name );
+       return false;
+    }
+
+    return true;
+}
+
+
+// close the port
+bool FGFile::close() {
+    if ( std::close( fp ) == -1 ) {
+       return false;
+    }
+
+    return true;
+}
diff --git a/src/Network/fg_file.hxx b/src/Network/fg_file.hxx
new file mode 100644 (file)
index 0000000..852fc49
--- /dev/null
@@ -0,0 +1,76 @@
+// fg_file.hxx -- File I/O routines
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#ifndef _FG_FILE_HXX
+#define _FG_FILE_HXX
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include "Include/compiler.h"
+
+#include <string>
+
+#include <sys/types.h>         // for open(), read(), write(), close()
+#include <sys/stat.h>          // for open(), read(), write(), close()
+#include <fcntl.h>             // for open(), read(), write(), close()
+#include <unistd.h>            // for open(), read(), write(), close()
+
+#include "iochannel.hxx"
+#include "protocol.hxx"
+
+FG_USING_STD(string);
+
+
+class FGFile : public FGIOChannel {
+
+    string file_name;
+    int fp;
+
+public:
+
+    FGFile();
+    ~FGFile();
+
+    // open the file based on specified direction
+    bool open( FGProtocol::fgProtocolDir dir );
+
+    // read data from file
+    bool read( char *buf, int *length );
+
+    // write data to a file
+    bool write( char *buf, int length );
+
+    // close file
+    bool close();
+
+    inline string get_file_name() const { return file_name; }
+    inline void set_file_name( const string& fn ) { file_name = fn; }
+};
+
+
+#endif // _FG_FILE_HXX
+
+
diff --git a/src/Network/fg_serial.cxx b/src/Network/fg_serial.cxx
new file mode 100644 (file)
index 0000000..713fdf3
--- /dev/null
@@ -0,0 +1,258 @@
+// fg_serial.cxx -- Serial I/O routines
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#include <Include/compiler.h>
+
+// #ifdef FG_HAVE_STD_INCLUDES
+// #  include <cmath>
+// #  include <cstdlib>    // atoi()
+// #else
+// #  include <math.h>
+// #  include <stdlib.h>   // atoi()
+// #endif
+
+#include STL_STRING
+
+#include <Debug/logstream.hxx>
+#include <Aircraft/aircraft.hxx>
+#include <Include/fg_constants.h>
+#include <Serial/serial.hxx>
+#include <Time/fg_time.hxx>
+
+// #include "options.hxx"
+
+#include "fg_serial.hxx"
+
+FG_USING_STD(string);
+
+
+FGSerial::FGSerial() {
+}
+
+
+FGSerial::~FGSerial() {
+}
+
+
+// open the serial port based on specified direction
+bool FGSerial::open( FGProtocol::fgProtocolDir dir ) {
+    if ( ! port.open_port( device ) ) {
+       FG_LOG( FG_IO, FG_ALERT, "Error opening device: " << device );
+       return false;
+    }
+
+    // cout << "fd = " << port.fd << endl;
+
+    if ( ! port.set_baud( atoi( baud.c_str() ) ) ) {
+       FG_LOG( FG_IO, FG_ALERT, "Error setting baud: " << baud );
+       return false;
+    }
+
+    return true;
+}
+
+
+#if 0
+// "RUL" output format (for some sort of motion platform)
+//
+// The Baud rate is 2400 , one start bit, eight data bits, 1 stop bit,
+// no parity.
+//
+// For position it requires a 3-byte data packet defined as follows:
+//
+// First bite: ascII character "P" ( 0x50 or 80 decimal )
+// Second byte X pos. (1-255) 1 being 0* and 255 being 359*
+// Third byte Y pos.( 1-255) 1 being 0* and 255 359*
+//
+// So sending 80 127 127 to the two axis motors will position on 180*
+// The RS- 232 port is a nine pin connector and the only pins used are
+// 3&5.
+
+static void send_rul_out( fgIOCHANNEL *p ) {
+    char rul[256];
+
+    FGInterface *f;
+    FGTime *t;
+
+    f = current_aircraft.fdm_state;
+    t = FGTime::cur_time_params;
+
+    // run as often as possibleonce per second
+
+    // this runs once per second
+    // if ( p->last_time == t->get_cur_time() ) {
+    //    return;
+    // }
+    // p->last_time = t->get_cur_time();
+    // if ( t->get_cur_time() % 2 != 0 ) {
+    //    return;
+    // }
+    
+    // get roll and pitch, convert to degrees
+    double roll_deg = f->get_Phi() * RAD_TO_DEG;
+    while ( roll_deg < -180.0 ) {
+       roll_deg += 360.0;
+    }
+    while ( roll_deg > 180.0 ) {
+       roll_deg -= 360.0;
+    }
+
+    double pitch_deg = f->get_Theta() * RAD_TO_DEG;
+    while ( pitch_deg < -180.0 ) {
+       pitch_deg += 360.0;
+    }
+    while ( pitch_deg > 180.0 ) {
+       pitch_deg -= 360.0;
+    }
+
+    // scale roll and pitch to output format (1 - 255)
+    // straight && level == (128, 128)
+
+    int roll = (int)( (roll_deg+180.0) * 255.0 / 360.0) + 1;
+    int pitch = (int)( (pitch_deg+180.0) * 255.0 / 360.0) + 1;
+
+    sprintf( rul, "p%c%c\n", roll, pitch);
+
+    FG_LOG( FG_IO, FG_INFO, "p " << roll << " " << pitch );
+
+    string rul_sentence = rul;
+    p->port.write_port(rul_sentence);
+}
+
+
+// "PVE" (ProVision Entertainment) output format (for some sort of
+// motion platform)
+//
+// Outputs a 5-byte data packet defined as follows:
+//
+// First bite:  ASCII character "P" ( 0x50 or 80 decimal )
+// Second byte:  "roll" value (1-255) 1 being 0* and 255 being 359*
+// Third byte:  "pitch" value (1-255) 1 being 0* and 255 being 359*
+// Fourth byte:  "heave" value (or vertical acceleration?)
+//
+// So sending 80 127 127 to the two axis motors will position on 180*
+// The RS- 232 port is a nine pin connector and the only pins used are
+// 3&5.
+
+static void send_pve_out( fgIOCHANNEL *p ) {
+    char pve[256];
+
+    FGInterface *f;
+    FGTime *t;
+
+
+    f = current_aircraft.fdm_state;
+    t = FGTime::cur_time_params;
+
+    // run as often as possibleonce per second
+
+    // this runs once per second
+    // if ( p->last_time == t->get_cur_time() ) {
+    //    return;
+    // }
+    // p->last_time = t->get_cur_time();
+    // if ( t->get_cur_time() % 2 != 0 ) {
+    //    return;
+    // }
+    
+    // get roll and pitch, convert to degrees
+    double roll_deg = f->get_Phi() * RAD_TO_DEG;
+    while ( roll_deg <= -180.0 ) {
+       roll_deg += 360.0;
+    }
+    while ( roll_deg > 180.0 ) {
+       roll_deg -= 360.0;
+    }
+
+    double pitch_deg = f->get_Theta() * RAD_TO_DEG;
+    while ( pitch_deg <= -180.0 ) {
+       pitch_deg += 360.0;
+    }
+    while ( pitch_deg > 180.0 ) {
+       pitch_deg -= 360.0;
+    }
+
+    short int heave = (int)(f->get_W_body() * 128.0);
+
+    // scale roll and pitch to output format (1 - 255)
+    // straight && level == (128, 128)
+
+    short int roll = (int)(roll_deg * 32768 / 180.0);
+    short int pitch = (int)(pitch_deg * 32768 / 180.0);
+
+    unsigned char roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2;
+    roll_b1 = roll >> 8;
+    roll_b2 = roll & 0x00ff;
+    pitch_b1 = pitch >> 8;
+    pitch_b2 = pitch & 0x00ff;
+    heave_b1 = heave >> 8;
+    heave_b2 = heave & 0x00ff;
+
+    sprintf( pve, "p%c%c%c%c%c%c\n", 
+            roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2 );
+
+    // printf( "p [ %u %u ]  [ %u %u ]  [ %u %u ]\n", 
+    //         roll_b1, roll_b2, pitch_b1, pitch_b2, heave_b1, heave_b2 );
+
+    FG_LOG( FG_IO, FG_INFO, "roll=" << roll << " pitch=" << pitch <<
+           " heave=" << heave );
+
+    string pve_sentence = pve;
+    p->port.write_port(pve_sentence);
+}
+
+#endif
+
+
+// read data from port
+bool FGSerial::read( char *buf, int *length ) {
+    // read a chunk
+    *length = port.read_port( buf );
+    
+    // just in case ...
+    buf[ *length ] = '\0';
+
+    return true;
+}
+
+// write data to port
+bool FGSerial::write( char *buf, int length ) {
+    int result = port.write_port( buf, length );
+
+    if ( result != length ) {
+       FG_LOG( FG_IO, FG_ALERT, "Error writing data: " << device );
+       return false;
+    }
+
+    return true;
+}
+
+
+// close the port
+bool FGSerial::close() {
+    if ( ! port.close_port() ) {
+       return false;
+    }
+
+    return true;
+}
diff --git a/src/Network/fg_serial.hxx b/src/Network/fg_serial.hxx
new file mode 100644 (file)
index 0000000..34075f7
--- /dev/null
@@ -0,0 +1,82 @@
+// fg_serial.hxx -- Serial I/O routines
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#ifndef _FG_SERIAL_HXX
+#define _FG_SERIAL_HXX
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include "Include/compiler.h"
+
+#include <string>
+
+// #ifdef FG_HAVE_STD_INCLUDES
+// #  include <ctime>
+// #else
+// #  include <time.h>
+// #endif
+
+#include <Serial/serial.hxx>
+
+#include "iochannel.hxx"
+#include "protocol.hxx"
+
+FG_USING_STD(string);
+
+
+class FGSerial : public FGIOChannel {
+
+    string device;
+    string baud;
+    FGSerialPort port;
+
+public:
+
+    FGSerial();
+    ~FGSerial();
+
+    // open the serial port based on specified direction
+    bool open( FGProtocol::fgProtocolDir dir );
+
+    // read data from port
+    bool read( char *buf, int *length );
+
+    // write data to port
+    bool write( char *buf, int length );
+
+    // close port
+    bool close();
+
+    inline string get_device() const { return device; }
+    inline void set_device( const string& d ) { device = d; }
+    inline string get_baud() const { return baud; }
+    inline void set_baud( const string& b ) { baud = b; }
+};
+
+
+#endif // _FG_SERIAL_HXX
+
+
diff --git a/src/Network/garmin.cxx b/src/Network/garmin.cxx
new file mode 100644 (file)
index 0000000..5611625
--- /dev/null
@@ -0,0 +1,405 @@
+// garmin.cxx -- Garmin protocal class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#include <Debug/logstream.hxx>
+#include <FDM/flight.hxx>
+#include <Math/fg_geodesy.hxx>
+#include <Time/fg_time.hxx>
+
+#include "iochannel.hxx"
+#include "garmin.hxx"
+
+
+FGGarmin::FGGarmin() {
+}
+
+FGGarmin::~FGGarmin() {
+}
+
+
+// calculate the garmin check sum
+static char calc_nmea_cksum(char *sentence) {
+    unsigned char sum = 0;
+    int i, len;
+
+    // cout << sentence << endl;
+
+    len = strlen(sentence);
+    sum = sentence[0];
+    for ( i = 1; i < len; i++ ) {
+        // cout << sentence[i];
+        sum ^= sentence[i];
+    }
+    // cout << endl;
+
+    // printf("sum = %02x\n", sum);
+    return sum;
+}
+
+
+// generate Garmin message
+bool FGGarmin::gen_message() {
+    // cout << "generating garmin message" << endl;
+
+    char rmc[256], rmc_sum[256], rmz[256], rmz_sum[256];
+    char dir;
+    int deg;
+    double min;
+
+    FGTime *t = FGTime::cur_time_params;
+
+    char utc[10];
+    sprintf( utc, "%02d%02d%02d", 
+            t->getGmt()->tm_hour, t->getGmt()->tm_min, t->getGmt()->tm_sec );
+
+    char lat[20];
+    double latd = cur_fdm_state->get_Latitude() * RAD_TO_DEG;
+    if ( latd < 0.0 ) {
+       latd *= -1.0;
+       dir = 'S';
+    } else {
+       dir = 'N';
+    }
+    deg = (int)(latd);
+    min = (latd - (double)deg) * 60.0;
+    sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
+
+    char lon[20];
+    double lond = cur_fdm_state->get_Longitude() * RAD_TO_DEG;
+    if ( lond < 0.0 ) {
+       lond *= -1.0;
+       dir = 'W';
+    } else {
+       dir = 'E';
+    }
+    deg = (int)(lond);
+    min = (lond - (double)deg) * 60.0;
+    sprintf( lon, "%03d%06.3f,%c", abs(deg), min, dir);
+
+    char speed[10];
+    sprintf( speed, "%05.1f", cur_fdm_state->get_V_equiv_kts() );
+
+    char heading[10];
+    sprintf( heading, "%05.1f", cur_fdm_state->get_Psi() * RAD_TO_DEG );
+
+    char altitude_m[10];
+    sprintf( altitude_m, "%02d", 
+            (int)(cur_fdm_state->get_Altitude() * FEET_TO_METER) );
+
+    char altitude_ft[10];
+    sprintf( altitude_ft, "%02d", (int)cur_fdm_state->get_Altitude() );
+
+    char date[10];
+    sprintf( date, "%02d%02d%02d", t->getGmt()->tm_mday, 
+            t->getGmt()->tm_mon+1, t->getGmt()->tm_year );
+
+    // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
+    sprintf( rmc, "GPRMC,%s,A,%s,%s,%s,%s,%s,000.0,E",
+            utc, lat, lon, speed, heading, date );
+    sprintf( rmc_sum, "%02X", calc_nmea_cksum(rmc) );
+
+    // sprintf( gga, "$GPGGA,%s,%s,%s,1,04,0.0,%s,M,00.0,M,,*00\r\n",
+    //          utc, lat, lon, altitude_m );
+
+    sprintf( rmz, "PGRMZ,%s,f,3", altitude_ft );
+    sprintf( rmz_sum, "%02X", calc_nmea_cksum(rmz) );
+
+    FG_LOG( FG_IO, FG_DEBUG, rmc );
+    FG_LOG( FG_IO, FG_DEBUG, rmz );
+
+    string garmin_sentence;
+
+    // RMC sentence
+    garmin_sentence = "$";
+    garmin_sentence += rmc;
+    garmin_sentence += "*";
+    garmin_sentence += rmc_sum;
+    garmin_sentence += "\n";
+
+    // RMZ sentence (garmin proprietary)
+    garmin_sentence += "$";
+    garmin_sentence += rmz;
+    garmin_sentence += "*";
+    garmin_sentence += rmz_sum;
+    garmin_sentence += "\n";
+
+    cout << garmin_sentence;
+
+    length = garmin_sentence.length();
+    strncpy( buf, garmin_sentence.c_str(), length );
+
+    return true;
+}
+
+
+// parse Garmin message
+bool FGGarmin::parse_message() {
+    FG_LOG( FG_IO, FG_DEBUG, "parse garmin message" );
+
+    string msg = buf;
+    msg = msg.substr( 0, length );
+    FG_LOG( FG_IO, FG_DEBUG, "entire message = " << msg );
+
+    string::size_type begin_line, end_line, begin, end;
+    begin_line = begin = 0;
+
+    // extract out each line
+    end_line = msg.find("\n", begin_line);
+    while ( end_line != string::npos ) {
+       string line = msg.substr(begin_line, end_line - begin_line);
+       begin_line = end_line + 1;
+       FG_LOG( FG_IO, FG_DEBUG, "  input line = " << line );
+
+       // leading character
+       string start = msg.substr(begin, 1);
+       ++begin;
+       FG_LOG( FG_IO, FG_DEBUG, "  start = " << start );
+
+       // sentence
+       end = msg.find(",", begin);
+       if ( end == string::npos ) {
+           return false;
+       }
+    
+       string sentence = msg.substr(begin, end - begin);
+       begin = end + 1;
+       FG_LOG( FG_IO, FG_DEBUG, "  sentence = " << sentence );
+
+       double lon_deg, lon_min, lat_deg, lat_min;
+       double lon, lat, speed, heading, altitude;
+
+       if ( sentence == "GPRMC" ) {
+           // time
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string utc = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_DEBUG, "  utc = " << utc );
+
+           // junk
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string junk = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_DEBUG, "  junk = " << junk );
+
+           // lat val
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lat_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lat_deg = atof( lat_str.substr(0, 2).c_str() );
+           lat_min = atof( lat_str.substr(2).c_str() );
+
+           // lat dir
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lat_dir = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lat = lat_deg + ( lat_min / 60.0 );
+           if ( lat_dir == "S" ) {
+               lat *= -1;
+           }
+
+           cur_fdm_state->set_Latitude( lat * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_DEBUG, "  lat = " << lat );
+
+           // lon val
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lon_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lon_deg = atof( lon_str.substr(0, 3).c_str() );
+           lon_min = atof( lon_str.substr(3).c_str() );
+
+           // lon dir
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lon_dir = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lon = lon_deg + ( lon_min / 60.0 );
+           if ( lon_dir == "W" ) {
+               lon *= -1;
+           }
+
+           cur_fdm_state->set_Longitude( lon * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_DEBUG, "  lon = " << lon );
+
+           double sl_radius, lat_geoc;
+           fgGeodToGeoc( cur_fdm_state->get_Latitude(), 
+                         cur_fdm_state->get_Altitude(), 
+                         &sl_radius, &lat_geoc );
+           cur_fdm_state->set_Geocentric_Position( lat_geoc, 
+                          cur_fdm_state->get_Longitude(), 
+                          sl_radius + cur_fdm_state->get_Altitude() );
+
+           // speed
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string speed_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+           speed = atof( speed_str.c_str() );
+           cur_fdm_state->set_V_equiv_kts( speed );
+           cur_fdm_state->set_V_ground_speed( speed );
+           FG_LOG( FG_IO, FG_DEBUG, "  speed = " << speed );
+
+           // heading
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string hdg_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+           heading = atof( hdg_str.c_str() );
+           cur_fdm_state->set_Euler_Angles( cur_fdm_state->get_Phi(), 
+                                            cur_fdm_state->get_Theta(), 
+                                            heading * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_DEBUG, "  heading = " << heading );
+       } else if ( sentence == "PGRMZ" ) {
+           // altitude
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string alt_str = msg.substr(begin, end - begin);
+           altitude = atof( alt_str.c_str() );
+           begin = end + 1;
+
+           // altitude units
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string alt_units = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           if ( alt_units != "F" && alt_units != "f" ) {
+               altitude *= METER_TO_FEET;
+           }
+
+           cur_fdm_state->set_Altitude( altitude );
+    
+           FG_LOG( FG_IO, FG_DEBUG, " altitude  = " << altitude );
+
+       }
+
+       // printf("%.8f %.8f\n", lon, lat);
+
+       begin = begin_line;
+       end_line = msg.find("\n", begin_line);
+    }
+
+    return true;
+}
+
+
+// open hailing frequencies
+bool FGGarmin::open() {
+    if ( is_enabled() ) {
+       FG_LOG( FG_IO, FG_ALERT, "This shouldn't happen, but the channel " 
+               << "is already in use, ignoring" );
+       return false;
+    }
+
+    FGIOChannel *io = get_io_channel();
+
+    if ( ! io->open( get_direction() ) ) {
+       FG_LOG( FG_IO, FG_ALERT, "Error opening channel communication layer." );
+       return false;
+    }
+
+    set_enabled( true );
+
+    return true;
+}
+
+
+// process work for this port
+bool FGGarmin::process() {
+    FGIOChannel *io = get_io_channel();
+
+    if ( get_direction() == out ) {
+       gen_message();
+       if ( ! io->write( buf, length ) ) {
+           FG_LOG( FG_IO, FG_ALERT, "Error writing data." );
+           return false;
+       }
+    } else if ( get_direction() == in ) {
+       if ( io->read( buf, &length ) ) {
+           parse_message();
+       } else {
+           FG_LOG( FG_IO, FG_ALERT, "Error reading data." );
+           return false;
+       }
+       if ( io->read( buf, &length ) ) {
+           parse_message();
+       } else {
+           FG_LOG( FG_IO, FG_ALERT, "Error reading data." );
+           return false;
+       }
+    }
+
+    return true;
+}
+
+
+// close the channel
+bool FGGarmin::close() {
+    FGIOChannel *io = get_io_channel();
+
+    set_enabled( false );
+
+    if ( ! io->close() ) {
+       return false;
+    }
+
+    return true;
+}
diff --git a/src/Network/garmin.hxx b/src/Network/garmin.hxx
new file mode 100644 (file)
index 0000000..901db37
--- /dev/null
@@ -0,0 +1,63 @@
+// garmin.hxx -- Garmin protocal class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#ifndef _FG_GARMIN_HXX
+#define _FG_GARMIN_HXX
+
+
+#include "Include/compiler.h"
+
+#include STL_STRING
+
+#include "protocol.hxx"
+
+FG_USING_STD(string);
+
+
+class FGGarmin : public FGProtocol {
+
+    char buf[ FG_MAX_MSG_SIZE ];
+    int length;
+
+public:
+
+    FGGarmin();
+    ~FGGarmin();
+
+    bool gen_message();
+    bool parse_message();
+    // open hailing frequencies
+    bool open();
+
+    // process work for this port
+    bool process();
+
+    // close the channel
+    bool close();
+};
+
+
+#endif // _FG_GARMIN_HXX
+
+
diff --git a/src/Network/iochannel.cxx b/src/Network/iochannel.cxx
new file mode 100644 (file)
index 0000000..c054f2c
--- /dev/null
@@ -0,0 +1,62 @@
+// iochannel.cxx -- High level IO channel class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#include "iochannel.hxx"
+#include "garmin.hxx"
+#include "nmea.hxx"
+
+
+// constructor
+FGIOChannel::FGIOChannel()
+{
+}
+
+
+// destructor
+FGIOChannel::~FGIOChannel()
+{
+}
+
+
+// dummy configure routine
+bool FGIOChannel::open( FGProtocol::fgProtocolDir dir ) {
+    return false;
+}
+
+
+// dummy process routine
+bool FGIOChannel::read( char *buf, int *length ) {
+    return false;
+}
+
+
+// dummy process routine
+bool FGIOChannel::write( char *buf, int length ) {
+    return false;
+}
+
+
+// dummy close routine
+bool FGIOChannel::close() {
+    return false;
+}
diff --git a/src/Network/iochannel.hxx b/src/Network/iochannel.hxx
new file mode 100644 (file)
index 0000000..ee125b2
--- /dev/null
@@ -0,0 +1,59 @@
+// iochannel.hxx -- High level IO channel class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#ifndef _IOCHANNEL_HXX
+#define _IOCHANNEL_HXX
+
+
+#include "Include/compiler.h"
+
+#include "protocol.hxx"
+
+#include STL_STRING
+#include <vector>
+
+FG_USING_STD(vector);
+FG_USING_STD(string);
+
+
+// forward declaration
+class FGProtocol;
+
+
+class FGIOChannel {
+
+public:
+
+    FGIOChannel();
+    virtual ~FGIOChannel();
+
+    virtual bool open( FGProtocol::fgProtocolDir dir );
+    virtual bool read( char *buf, int *length );
+    virtual bool write( char *buf, int length );
+    virtual bool close();
+};
+
+
+#endif // _IOCHANNEL_HXX
+
+
diff --git a/src/Network/nmea.cxx b/src/Network/nmea.cxx
new file mode 100644 (file)
index 0000000..3da8ce4
--- /dev/null
@@ -0,0 +1,502 @@
+// nmea.cxx -- NMEA protocal class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#include <Debug/logstream.hxx>
+#include <FDM/flight.hxx>
+#include <Math/fg_geodesy.hxx>
+#include <Time/fg_time.hxx>
+
+#include "iochannel.hxx"
+#include "nmea.hxx"
+
+
+FGNMEA::FGNMEA() {
+}
+
+FGNMEA::~FGNMEA() {
+}
+
+
+// calculate the nmea check sum
+static char calc_nmea_cksum(char *sentence) {
+    unsigned char sum = 0;
+    int i, len;
+
+    // cout << sentence << endl;
+
+    len = strlen(sentence);
+    sum = sentence[0];
+    for ( i = 1; i < len; i++ ) {
+        // cout << sentence[i];
+        sum ^= sentence[i];
+    }
+    // cout << endl;
+
+    // printf("sum = %02x\n", sum);
+    return sum;
+}
+
+
+// generate NMEA message
+bool FGNMEA::gen_message() {
+    // cout << "generating nmea message" << endl;
+
+    char rmc[256], gga[256];
+    char rmc_sum[10], gga_sum[10];
+    char dir;
+    int deg;
+    double min;
+
+    FGTime *t = FGTime::cur_time_params;
+
+    char utc[10];
+    sprintf( utc, "%02d%02d%02d", 
+            t->getGmt()->tm_hour, t->getGmt()->tm_min, t->getGmt()->tm_sec );
+
+    char lat[20];
+    double latd = cur_fdm_state->get_Latitude() * RAD_TO_DEG;
+    if ( latd < 0.0 ) {
+       latd *= -1.0;
+       dir = 'S';
+    } else {
+       dir = 'N';
+    }
+    deg = (int)(latd);
+    min = (latd - (double)deg) * 60.0;
+    sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
+
+    char lon[20];
+    double lond = cur_fdm_state->get_Longitude() * RAD_TO_DEG;
+    if ( lond < 0.0 ) {
+       lond *= -1.0;
+       dir = 'W';
+    } else {
+       dir = 'E';
+    }
+    deg = (int)(lond);
+    min = (lond - (double)deg) * 60.0;
+    sprintf( lon, "%03d%06.3f,%c", abs(deg), min, dir);
+
+    char speed[10];
+    sprintf( speed, "%05.1f", cur_fdm_state->get_V_equiv_kts() );
+
+    char heading[10];
+    sprintf( heading, "%05.1f", cur_fdm_state->get_Psi() * RAD_TO_DEG );
+
+    char altitude_m[10];
+    sprintf( altitude_m, "%02d", 
+            (int)(cur_fdm_state->get_Altitude() * FEET_TO_METER) );
+
+    char altitude_ft[10];
+    sprintf( altitude_ft, "%02d", (int)cur_fdm_state->get_Altitude() );
+
+    char date[10];
+    sprintf( date, "%02d%02d%02d", t->getGmt()->tm_mday, 
+            t->getGmt()->tm_mon+1, t->getGmt()->tm_year );
+
+    // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
+    sprintf( rmc, "GPRMC,%s,A,%s,%s,%s,%s,%s,0.000,E",
+            utc, lat, lon, speed, heading, date );
+    sprintf( rmc_sum, "%02X", calc_nmea_cksum(rmc) );
+
+    sprintf( gga, "GPGGA,%s,%s,%s,1,,,%s,F,,,,",
+            utc, lat, lon, altitude_ft );
+    sprintf( gga_sum, "%02X", calc_nmea_cksum(gga) );
+
+
+    FG_LOG( FG_IO, FG_DEBUG, rmc );
+    FG_LOG( FG_IO, FG_DEBUG, gga );
+
+    string nmea_sentence;
+
+    // RMC sentence
+    nmea_sentence = "$";
+    nmea_sentence += rmc;
+    nmea_sentence += "*";
+    nmea_sentence += rmc_sum;
+    nmea_sentence += "\n";
+
+    // GGA sentence
+    nmea_sentence += "$";
+    nmea_sentence += gga;
+    nmea_sentence += "*";
+    nmea_sentence += gga_sum;
+    nmea_sentence += "\n";
+
+    cout << nmea_sentence;
+
+    length = nmea_sentence.length();
+    strncpy( buf, nmea_sentence.c_str(), length );
+
+    return true;
+}
+
+
+// parse NMEA message.  messages will look something like the
+// following:
+//
+// $GPRMC,163227,A,3321.173,N,11039.855,W,000.1,270.0,171199,0.000,E*61
+// $GPGGA,163227,3321.173,N,11039.855,W,1,,,3333,F,,,,*0F
+
+bool FGNMEA::parse_message() {
+    FG_LOG( FG_IO, FG_INFO, "parse nmea message" );
+
+    string msg = buf;
+    msg = msg.substr( 0, length );
+    FG_LOG( FG_IO, FG_INFO, "entire message = " << msg );
+
+    string::size_type begin_line, end_line, begin, end;
+    begin_line = begin = 0;
+
+    // extract out each line
+    end_line = msg.find("\n", begin_line);
+    while ( end_line != string::npos ) {
+       string line = msg.substr(begin_line, end_line - begin_line);
+       begin_line = end_line + 1;
+       FG_LOG( FG_IO, FG_INFO, "  input line = " << line );
+
+       // leading character
+       string start = msg.substr(begin, 1);
+       ++begin;
+       FG_LOG( FG_IO, FG_INFO, "  start = " << start );
+
+       // sentence
+       end = msg.find(",", begin);
+       if ( end == string::npos ) {
+           return false;
+       }
+    
+       string sentence = msg.substr(begin, end - begin);
+       begin = end + 1;
+       FG_LOG( FG_IO, FG_INFO, "  sentence = " << sentence );
+
+       double lon_deg, lon_min, lat_deg, lat_min;
+       double lon, lat, speed, heading, altitude;
+
+       if ( sentence == "GPRMC" ) {
+           // time
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string utc = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_INFO, "  utc = " << utc );
+
+           // junk
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string junk = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_INFO, "  junk = " << junk );
+
+           // lat val
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lat_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lat_deg = atof( lat_str.substr(0, 2).c_str() );
+           lat_min = atof( lat_str.substr(2).c_str() );
+
+           // lat dir
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lat_dir = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lat = lat_deg + ( lat_min / 60.0 );
+           if ( lat_dir == "S" ) {
+               lat *= -1;
+           }
+
+           cur_fdm_state->set_Latitude( lat * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_INFO, "  lat = " << lat );
+
+           // lon val
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lon_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lon_deg = atof( lon_str.substr(0, 3).c_str() );
+           lon_min = atof( lon_str.substr(3).c_str() );
+
+           // lon dir
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lon_dir = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lon = lon_deg + ( lon_min / 60.0 );
+           if ( lon_dir == "W" ) {
+               lon *= -1;
+           }
+
+           cur_fdm_state->set_Longitude( lon * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_INFO, "  lon = " << lon );
+
+           double sl_radius, lat_geoc;
+           fgGeodToGeoc( cur_fdm_state->get_Latitude(), 
+                         cur_fdm_state->get_Altitude(), 
+                         &sl_radius, &lat_geoc );
+           cur_fdm_state->set_Geocentric_Position( lat_geoc, 
+                          cur_fdm_state->get_Longitude(), 
+                          sl_radius + cur_fdm_state->get_Altitude() );
+
+           // speed
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string speed_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+           speed = atof( speed_str.c_str() );
+           cur_fdm_state->set_V_equiv_kts( speed );
+           cur_fdm_state->set_V_ground_speed( speed );
+           FG_LOG( FG_IO, FG_INFO, "  speed = " << speed );
+
+           // heading
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string hdg_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+           heading = atof( hdg_str.c_str() );
+           cur_fdm_state->set_Euler_Angles( cur_fdm_state->get_Phi(), 
+                                            cur_fdm_state->get_Theta(), 
+                                            heading * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_INFO, "  heading = " << heading );
+       } else if ( sentence == "GPGGA" ) {
+           // time
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string utc = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_INFO, "  utc = " << utc );
+
+           // lat val
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lat_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lat_deg = atof( lat_str.substr(0, 2).c_str() );
+           lat_min = atof( lat_str.substr(2).c_str() );
+
+           // lat dir
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lat_dir = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lat = lat_deg + ( lat_min / 60.0 );
+           if ( lat_dir == "S" ) {
+               lat *= -1;
+           }
+
+           // cur_fdm_state->set_Latitude( lat * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_INFO, "  lat = " << lat );
+
+           // lon val
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lon_str = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lon_deg = atof( lon_str.substr(0, 3).c_str() );
+           lon_min = atof( lon_str.substr(3).c_str() );
+
+           // lon dir
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string lon_dir = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           lon = lon_deg + ( lon_min / 60.0 );
+           if ( lon_dir == "W" ) {
+               lon *= -1;
+           }
+
+           // cur_fdm_state->set_Longitude( lon * DEG_TO_RAD );
+           FG_LOG( FG_IO, FG_INFO, "  lon = " << lon );
+
+           // junk
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string junk = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_INFO, "  junk = " << junk );
+
+           // junk
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           junk = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_INFO, "  junk = " << junk );
+
+           // junk
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           junk = msg.substr(begin, end - begin);
+           begin = end + 1;
+           FG_LOG( FG_IO, FG_INFO, "  junk = " << junk );
+
+           // altitude
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string alt_str = msg.substr(begin, end - begin);
+           altitude = atof( alt_str.c_str() );
+           begin = end + 1;
+
+           // altitude units
+           end = msg.find(",", begin);
+           if ( end == string::npos ) {
+               return false;
+           }
+    
+           string alt_units = msg.substr(begin, end - begin);
+           begin = end + 1;
+
+           if ( alt_units != "F" ) {
+               altitude *= METER_TO_FEET;
+           }
+
+           cur_fdm_state->set_Altitude( altitude );
+    
+           FG_LOG( FG_IO, FG_INFO, " altitude  = " << altitude );
+
+       }
+
+       // printf("%.8f %.8f\n", lon, lat);
+
+       begin = begin_line;
+       end_line = msg.find("\n", begin_line);
+    }
+
+    return true;
+}
+
+
+// open hailing frequencies
+bool FGNMEA::open() {
+    if ( is_enabled() ) {
+       FG_LOG( FG_IO, FG_ALERT, "This shouldn't happen, but the channel " 
+               << "is already in use, ignoring" );
+       return false;
+    }
+
+    FGIOChannel *io = get_io_channel();
+
+    if ( ! io->open( get_direction() ) ) {
+       FG_LOG( FG_IO, FG_ALERT, "Error opening channel communication layer." );
+       return false;
+    }
+
+    set_enabled( true );
+
+    return true;
+}
+
+
+// process work for this port
+bool FGNMEA::process() {
+    FGIOChannel *io = get_io_channel();
+
+    if ( get_direction() == out ) {
+       gen_message();
+       if ( ! io->write( buf, length ) ) {
+           FG_LOG( FG_IO, FG_ALERT, "Error writing data." );
+           return false;
+       }
+    } else if ( get_direction() == in ) {
+       if ( io->read( buf, &length ) ) {
+           parse_message();
+       } else {
+           FG_LOG( FG_IO, FG_ALERT, "Error reading data." );
+           return false;
+       }
+    }
+
+    return true;
+}
+
+
+// close the channel
+bool FGNMEA::close() {
+    FGIOChannel *io = get_io_channel();
+
+    set_enabled( false );
+
+    if ( ! io->close() ) {
+       return false;
+    }
+
+    return true;
+}
diff --git a/src/Network/nmea.hxx b/src/Network/nmea.hxx
new file mode 100644 (file)
index 0000000..d480b12
--- /dev/null
@@ -0,0 +1,63 @@
+// nmea.hxx -- NMEA protocal class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#ifndef _FG_NMEA_HXX
+#define _FG_NMEA_HXX
+
+
+#include "Include/compiler.h"
+
+#include STL_STRING
+
+#include "protocol.hxx"
+
+FG_USING_STD(string);
+
+
+class FGNMEA : public FGProtocol {
+
+    char buf[ FG_MAX_MSG_SIZE ];
+    int length;
+
+public:
+
+    FGNMEA();
+    ~FGNMEA();
+
+    bool gen_message();
+    bool parse_message();
+
+    // open hailing frequencies
+    bool open();
+
+    // process work for this port
+    bool process();
+
+    // close the channel
+    bool close();
+};
+
+
+#endif // _FG_NMEA_HXX
+
+
diff --git a/src/Network/protocol.cxx b/src/Network/protocol.cxx
new file mode 100644 (file)
index 0000000..2954f04
--- /dev/null
@@ -0,0 +1,76 @@
+// protocol.cxx -- High level protocal class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#include <Debug/logstream.hxx>
+
+#include "protocol.hxx"
+
+
+FGProtocol::FGProtocol() :
+    hz(0.0),
+    count_down(0),
+    enabled(false)
+{
+}
+
+
+FGProtocol::~FGProtocol() {
+}
+
+
+// dummy open routine
+bool FGProtocol::open() {
+    FG_LOG( FG_IO, FG_INFO, "dummy FGProtocol::open()" );
+    enabled = false;
+    return false;
+}
+
+
+// dummy process routine
+bool FGProtocol::process() {
+    FG_LOG( FG_IO, FG_INFO, "dummy FGProtocol::process()" );
+    return false;
+}
+
+
+// dummy close routine
+bool FGProtocol::close() {
+    FG_LOG( FG_IO, FG_INFO, "dummy FGProtocol::close()" );
+    return false;
+}
+
+
+// dummy close routine
+bool FGProtocol::gen_message() {
+    FG_LOG( FG_IO, FG_INFO, "dummy FGProtocol::gen_message()" );
+    return false;
+}
+
+
+// dummy close routine
+bool FGProtocol::parse_message() {
+    FG_LOG( FG_IO, FG_INFO, "dummy FGProtocol::close()" );
+    return false;
+}
+
+
diff --git a/src/Network/protocol.hxx b/src/Network/protocol.hxx
new file mode 100644 (file)
index 0000000..1fcc959
--- /dev/null
@@ -0,0 +1,123 @@
+// protocol.hxx -- High level protocal class
+//
+// Written by Curtis Olson, started November 1999.
+//
+// Copyright (C) 1999  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$
+
+
+#ifndef _PROTOCOL_HXX
+#define _PROTOCOL_HXX
+
+
+#include "Include/compiler.h"
+
+#include STL_STRING
+#include <vector>
+
+FG_USING_STD(string);
+FG_USING_STD(vector);
+
+
+#define FG_MAX_MSG_SIZE 16384
+
+// forward declaration
+class FGIOChannel;
+
+
+class FGProtocol {
+
+public:
+
+    enum fgProtocolDir {
+       none = 0,
+       in = 1,
+       out = 2,
+       bi = 3
+    };
+
+private:
+
+    double hz;
+    int count_down;
+
+    fgProtocolDir dir;
+
+    // string protocol_str;
+
+    // char buf[FG_MAX_MSG_SIZE];
+    // int length;
+
+    bool enabled;
+
+    FGIOChannel *io;
+
+public:
+
+    FGProtocol();
+    virtual ~FGProtocol();
+
+    virtual bool open();
+    virtual bool process();
+    virtual bool close();
+
+    inline fgProtocolDir get_direction() const { return dir; }
+    inline void set_direction( const string& d ) {
+       if ( d == "in" ) {
+           dir = in;
+       } else if ( d == "out" ) {
+           dir = out;
+       } else if ( d == "bi" ) {
+           dir = bi;
+       } else {
+           dir = none;
+       }
+    }
+
+    inline double get_hz() const { return hz; }
+    inline void set_hz( double t ) { hz = t; }
+    inline int get_count_down() const { return count_down; }
+    inline void set_count_down( int c ) { count_down = c; }
+    inline void dec_count_down( int c ) { count_down -= c; }
+
+    virtual bool gen_message();
+    virtual bool parse_message();
+
+    // inline string get_protocol() const { return protocol_str; }
+    // inline void set_protocol( const string& str ) { protocol_str = str; }
+
+    // inline char *get_buf() { return buf; }
+    // inline int get_length() const { return length; }
+    // inline void set_length( int l ) { length = l; }
+
+    inline bool is_enabled() const { return enabled; }
+    inline void set_enabled( const bool b ) { enabled = b; }
+
+    inline FGIOChannel *get_io_channel() const { return io; }
+    inline void set_io_channel( FGIOChannel *c ) { io = c; }
+};
+
+
+typedef vector < FGProtocol * > io_container;
+typedef io_container::iterator io_iterator;
+typedef io_container::const_iterator const_io_iterator;
+
+
+#endif // _PROTOCOL_HXX
+
+