]> git.mxchange.org Git - flightgear.git/blobdiff - Main/fg_serial.cxx
Tweaked FDM interface.
[flightgear.git] / Main / fg_serial.cxx
index a0437a975f86bd1a3cafc87732b4b33ae02978f8..1516e85af2776ebaffef3eb16b54dbf92765fa2b 100644 (file)
 // (Log is kept at end of this file)
 
 
-#include <stdlib.h>   // atoi()
-#include <string>
+#include <Include/compiler.h>
+
+#ifdef FG_HAVE_STD_INCLUDES
+#  include <cstdlib>    // atoi()
+#else
+#  include <stdlib.h>   // atoi()
+#endif
+
+#include STL_STRING
+#include STL_IOSTREAM                                           
+#include <vector>                                                               
+#include "Include/fg_stl_config.h"                                              
+
+FG_USING_NAMESPACE(std);
 
 #include <Aircraft/aircraft.hxx>
 #include <Debug/logstream.hxx>
 #include "fg_serial.hxx"
 
 
-// support up to four serial channels.  Each channel can be assigned
-// to an arbitrary port.  Bi-directional communication is supported by
-// the underlying layer.
+// 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
-fgSERIAL port_a;
-fgSERIAL port_b;
-fgSERIAL port_c;
-fgSERIAL port_d;
+io_container port_list;
 
-// the type of each channel
-fgSerialPortKind port_a_kind = FG_SERIAL_DISABLED;
-fgSerialPortKind port_b_kind = FG_SERIAL_DISABLED;
-fgSerialPortKind port_c_kind = FG_SERIAL_DISABLED;
-fgSerialPortKind port_d_kind = FG_SERIAL_DISABLED;
+
+fgIOCHANNEL::fgIOCHANNEL() :
+    kind( FG_SERIAL_DISABLED ),
+    valid_config( false )
+{
+}
+
+
+fgIOCHANNEL::~fgIOCHANNEL() {
+}
 
 
 // configure a port based on the config string
-static bool config_port(fgSERIAL& s, fgSerialPortKind& kind,
-                                   const string& config)
+static fgIOCHANNEL parse_port_config( const string& config )
 {
+    fgIOCHANNEL p;
+
     string::size_type begin, end;
 
-    string device;
-    string format;
-    string baud;
-    string direction;
+    begin = 0;
 
-    begin = 0;;
+    FG_LOG( FG_SERIAL, FG_INFO, "Parse serial port config: " << config );
 
     // device name
     end = config.find(",", begin);
     if ( end == string::npos ) {
-       return false;
+       return p;
     }
     
-    device = config.substr(begin, end - begin);
+    p.device = config.substr(begin, end - begin);
     begin = end + 1;
-    cout << "  device = " << device << endl;
+    FG_LOG( FG_SERIAL, FG_INFO, "  device = " << p.device );
 
     // format
     end = config.find(",", begin);
     if ( end == string::npos ) {
-       return false;
+       return p;
     }
     
-    format = config.substr(begin, end - begin);
+    p.format = config.substr(begin, end - begin);
     begin = end + 1;
-    cout << "  format = " << format << endl;
+    FG_LOG( FG_SERIAL, FG_INFO, "  format = " << p.format );
 
     // baud
     end = config.find(",", begin);
     if ( end == string::npos ) {
-       return false;
+       return p;
     }
     
-    baud = config.substr(begin, end - begin);
+    p.baud = config.substr(begin, end - begin);
     begin = end + 1;
-    cout << "  baud = " << baud << endl;
+    FG_LOG( FG_SERIAL, FG_INFO, "  baud = " << p.baud );
 
     // direction
-    direction = config.substr(begin);
-    cout << "  direction = " << direction << endl;
+    p.direction = config.substr(begin);
+    FG_LOG( FG_SERIAL, FG_INFO, "  direction = " << p.direction );
+
+    p.valid_config = true;
+
+    return p;
+}
 
-    if ( s.is_enabled() ) {
+
+// 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 ( ! s.open_port( device ) ) {
-       FG_LOG( FG_SERIAL, FG_ALERT, "Error opening device: " << device );
+    if ( ! p.port.open_port( p.device ) ) {
+       FG_LOG( FG_SERIAL, FG_ALERT, "Error opening device: " << p.device );
+       return false;
     }
 
-    if ( ! s.set_baud( atoi( baud.c_str() ) ) ) {
-       FG_LOG( FG_SERIAL, FG_ALERT, "Error setting baud: " << baud );
+    // 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 ( format == "nmea" ) {
-       if ( direction == "out" ) {
-           kind = FG_SERIAL_NMEA_OUT;
-       } else if ( direction == "in" ) {
-           kind = FG_SERIAL_NMEA_IN;
+    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 ( format == "garman" ) {
-       if ( direction == "out" ) {
-           kind = FG_SERIAL_GARMAN_OUT;
-       } else if ( direction == "in" ) {
-           kind = FG_SERIAL_GARMAN_IN;
+    } 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 ( format == "fgfs" ) {
-       if ( direction == "out" ) {
-           kind = FG_SERIAL_FGFS_OUT;
-       } else if ( direction == "in" ) {
-           kind = FG_SERIAL_FGFS_IN;
+    } 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;
@@ -150,22 +180,29 @@ static bool config_port(fgSERIAL& s, fgSerialPortKind& kind,
 }
 
 
-// initialize serial ports based on command line options (if any)
+// step through the port config streams (from fgOPTIONS) and setup
+// serial port channels for each
 void fgSerialInit() {
-    if ( current_options.get_port_a_config() != "" ) {
-       config_port(port_a, port_a_kind, current_options.get_port_a_config() );
-    }
-
-    if ( current_options.get_port_b_config() != "" ) {
-       config_port(port_b, port_b_kind, current_options.get_port_b_config() );
-    }
-
-    if ( current_options.get_port_c_config() != "" ) {
-       config_port(port_c, port_c_kind, current_options.get_port_c_config() );
-    }
-
-    if ( current_options.get_port_d_config() != "" ) {
-       config_port(port_d, port_d_kind, current_options.get_port_d_config() );
+    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 );
+           }
+       }
     }
 }
 
@@ -189,16 +226,25 @@ char calc_nmea_cksum(char *sentence) {
 }
 
 
-static void send_nmea_out( fgSERIAL& s ) {
+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;
-    fgFLIGHT *f;
+    FGState *f;
     fgTIME *t;
 
-    f = current_aircraft.flight;
+    // run once every two seconds
+    if ( p.last_time == cur_time_params.cur_time ) {
+       return;
+    }
+    p.last_time = cur_time_params.cur_time;
+    if ( cur_time_params.cur_time % 2 != 0 ) {
+       return;
+    }
+
+    f = current_aircraft.fdm_state;
     t = &cur_time_params;
 
     char utc[10];
@@ -206,7 +252,7 @@ static void send_nmea_out( fgSERIAL& s ) {
             t->gmt->tm_hour, t->gmt->tm_min, t->gmt->tm_sec );
 
     char lat[20];
-    double latd = FG_Latitude * RAD_TO_DEG;
+    double latd = f->get_Latitude() * RAD_TO_DEG;
     if ( latd < 0.0 ) {
        latd *= -1.0;
        dir = 'S';
@@ -218,7 +264,7 @@ static void send_nmea_out( fgSERIAL& s ) {
     sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
 
     char lon[20];
-    double lond = FG_Longitude * RAD_TO_DEG;
+    double lond = f->get_Longitude() * RAD_TO_DEG;
     if ( lond < 0.0 ) {
        lond *= -1.0;
        dir = 'W';
@@ -227,19 +273,19 @@ static void send_nmea_out( fgSERIAL& s ) {
     }
     deg = (int)(lond);
     min = (lond - (double)deg) * 60.0;
-    sprintf( lon, "%02d%06.3f,%c", abs(deg), min, dir);
+    sprintf( lon, "%03d%06.3f,%c", abs(deg), min, dir);
 
     char speed[10];
-    sprintf( speed, "%05.1f", FG_V_equiv_kts );
+    sprintf( speed, "%05.1f", f->get_V_equiv_kts() );
 
     char heading[10];
-    sprintf( heading, "%05.1f", FG_Psi * RAD_TO_DEG );
+    sprintf( heading, "%05.1f", f->get_Psi() * RAD_TO_DEG );
 
     char altitude_m[10];
-    sprintf( altitude_m, "%02d", (int)(FG_Altitude * FEET_TO_METER) );
+    sprintf( altitude_m, "%02d", (int)(f->get_Altitude() * FEET_TO_METER) );
 
     char altitude_ft[10];
-    sprintf( altitude_ft, "%02d", (int)FG_Altitude );
+    sprintf( altitude_ft, "%02d", (int)f->get_Altitude() );
 
     char date[10];
     sprintf( date, "%02d%02d%02d", 
@@ -248,48 +294,56 @@ static void send_nmea_out( fgSERIAL& s ) {
     // $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", 0 /*calc_nmea_cksum(rmc)*/ );
+    sprintf( rmc_sum, "%02X", calc_nmea_cksum(rmc) );
 
-    sprintf( gga, "GPGGA,%s,%s,%s,1,,,%s,M,,,,",
-            utc, lat, lon, altitude_m );
-    sprintf( gga_sum, "%02X", 0 /*calc_nmea_cksum(gga)*/ );
+    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 );
 
-    // one full frame every 2 seconds according to the standard
-    if ( cur_time_params.cur_time % 2 == 0 ) {
-       // rmc on even seconds
-       string rmc_sentence = "$";
-       rmc_sentence += rmc;
-       rmc_sentence += "*";
-       rmc_sentence += rmc_sum;
-       rmc_sentence += "\r\n";
-       s.write_port(rmc_sentence);
-    } else {
-       // gga on odd seconds
-       string gga_sentence = "$";
-       gga_sentence += gga;
-       gga_sentence += "*";
-       gga_sentence += gga_sum;
-       gga_sentence += "\n";
-       // s.write_port(gga_sentence);
-    }
+    // 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( fgSERIAL& s ) {
+static void read_nmea_in( fgIOCHANNEL& p ) {
 }
 
-static void send_garman_out( fgSERIAL& s ) {
+static void send_garmin_out( fgIOCHANNEL& p ) {
     char rmc[256], rmz[256];
     char dir;
     int deg;
     double min;
-    fgFLIGHT *f;
+    FGState *f;
     fgTIME *t;
 
-    f = current_aircraft.flight;
+    // run once per second
+    if ( p.last_time == cur_time_params.cur_time ) {
+       return;
+    }
+    p.last_time = cur_time_params.cur_time;
+    if ( cur_time_params.cur_time % 2 != 0 ) {
+       return;
+    }
+    
+    f = current_aircraft.fdm_state;
     t = &cur_time_params;
 
     char utc[10];
@@ -297,7 +351,7 @@ static void send_garman_out( fgSERIAL& s ) {
             t->gmt->tm_hour, t->gmt->tm_min, t->gmt->tm_sec );
 
     char lat[20];
-    double latd = FG_Latitude * RAD_TO_DEG;
+    double latd = f->get_Latitude() * RAD_TO_DEG;
     if ( latd < 0.0 ) {
        latd *= -1.0;
        dir = 'S';
@@ -309,7 +363,7 @@ static void send_garman_out( fgSERIAL& s ) {
     sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
 
     char lon[20];
-    double lond = FG_Longitude * RAD_TO_DEG;
+    double lond = f->get_Longitude() * RAD_TO_DEG;
     if ( lond < 0.0 ) {
        lond *= -1.0;
        dir = 'W';
@@ -318,19 +372,19 @@ static void send_garman_out( fgSERIAL& s ) {
     }
     deg = (int)(lond);
     min = (lond - (double)deg) * 60.0;
-    sprintf( lon, "%02d%06.3f,%c", abs(deg), min, dir);
+    sprintf( lon, "%03d%06.3f,%c", abs(deg), min, dir);
 
     char speed[10];
-    sprintf( speed, "%05.1f", FG_V_equiv_kts );
+    sprintf( speed, "%05.1f", f->get_V_equiv_kts() );
 
     char heading[10];
-    sprintf( heading, "%05.1f", FG_Psi * RAD_TO_DEG );
+    sprintf( heading, "%05.1f", f->get_Psi() * RAD_TO_DEG );
 
     char altitude_m[10];
-    sprintf( altitude_m, "%02d", (int)(FG_Altitude * FEET_TO_METER) );
+    sprintf( altitude_m, "%02d", (int)(f->get_Altitude() * FEET_TO_METER) );
 
     char altitude_ft[10];
-    sprintf( altitude_ft, "%02d", (int)FG_Altitude );
+    sprintf( altitude_ft, "%02d", (int)f->get_Altitude() );
 
     char date[10];
     sprintf( date, "%02d%02d%02d", 
@@ -348,78 +402,84 @@ static void send_garman_out( fgSERIAL& s ) {
     FG_LOG( FG_SERIAL, FG_DEBUG, rmc );
     FG_LOG( FG_SERIAL, FG_DEBUG, rmz );
 
+    // RMC sentence
+    p.port.write_port(rmc);
+    cout << rmc;
 
-    // one full frame every 2 seconds according to the standard
-    if ( cur_time_params.cur_time % 2 == 0 ) {
-       // rmc on even seconds
-       s.write_port(rmc);
-    } else {
-       // gga on odd seconds
-       s.write_port(rmz);
-    }
+    // RMZ sentence (garmin proprietary)
+    p.port.write_port(rmz);
+    cout << rmz;
 }
 
-static void read_garman_in( fgSERIAL& s ) {
+static void read_garmin_in( fgIOCHANNEL& p ) {
 }
 
-static void send_fgfs_out( fgSERIAL& s ) {
+static void send_fgfs_out( fgIOCHANNEL& p ) {
 }
 
-static void read_fgfs_in( fgSERIAL& s ) {
+static void read_fgfs_in( fgIOCHANNEL& p ) {
 }
 
 
 // one more level of indirection ...
-static void process_port( fgSERIAL& s, const fgSerialPortKind kind ) {
-    static long last_time;
-    if ( kind == FG_SERIAL_NMEA_OUT ) {
-       if (cur_time_params.cur_time > last_time ) {
-           send_nmea_out(s);
-       } 
-       last_time = cur_time_params.cur_time;
-    } else if ( kind == FG_SERIAL_NMEA_IN ) {
-       read_nmea_in(s);
-    } else if ( kind == FG_SERIAL_GARMAN_OUT ) {
-       if (cur_time_params.cur_time > last_time ) {
-           send_garman_out(s);
-       } 
-       last_time = cur_time_params.cur_time;
-    } else if ( kind == FG_SERIAL_GARMAN_IN ) {
-       read_garman_in(s);
-    } else if ( kind == FG_SERIAL_FGFS_OUT ) {
-       send_fgfs_out(s);
-    } else if ( kind == FG_SERIAL_FGFS_IN ) {
-       read_fgfs_in(s);
+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);
     }
 }
 
 
 // process any serial port work
 void fgSerialProcess() {
-    if ( port_a_kind != FG_SERIAL_DISABLED ) {
-       process_port(port_a, port_a_kind);
-    }
-
-    if ( port_b_kind != FG_SERIAL_DISABLED ) {
-       process_port(port_b, port_b_kind);
-    }
-
-    if ( port_c_kind != FG_SERIAL_DISABLED ) {
-       process_port(port_c, port_c_kind);
-    }
+    fgIOCHANNEL port;
+    
+    const_io_iterator current = port_list.begin();
+    const_io_iterator last = port_list.end();
 
-    if ( port_d_kind != FG_SERIAL_DISABLED ) {
-       process_port(port_d, port_d_kind);
+    for ( ; current != last; ++current ) {
+       port = *current;
+       if ( port.kind != fgIOCHANNEL::FG_SERIAL_DISABLED ) {
+           process_port ( port );
+       }
     }
 }
 
 
 // $Log$
+// Revision 1.9  1999/01/20 13:42:26  curt
+// Tweaked FDM interface.
+// Testing check sum support for NMEA serial output.
+//
+// Revision 1.8  1999/01/19 20:57:04  curt
+// MacOS portability changes contributed by "Robert Puyol" <puyol@abvent.fr>
+//
+// Revision 1.7  1998/12/05 15:54:21  curt
+// Renamed class fgFLIGHT to class FGState as per request by JSB.
+//
+// Revision 1.6  1998/12/03 01:17:18  curt
+// Converted fgFLIGHT to a class.
+//
+// Revision 1.5  1998/11/30 17:43:32  curt
+// Lots of tweaking to get serial output to actually work.
+//
+// Revision 1.4  1998/11/25 01:33:58  curt
+// Support for an arbitrary number of serial ports.
+//
 // Revision 1.3  1998/11/23 20:51:51  curt
 // Tweaking serial stuff.
 //
 // Revision 1.2  1998/11/19 13:53:25  curt
-// Added a "Garman" mode.
+// Added a "Garmin" mode.
 //
 // Revision 1.1  1998/11/16 13:57:42  curt
 // Initial revision.