1
0
Fork 0

Add support for IGC logging protocol.

Many light aircraft include GPS loggers capable of recording the flight
path using IGC records. Lots of third party utilities are available to
analyze, process and convert igc files.
Usage: "fgfs --igc=file,out,1,OutputFile.igc"
This commit is contained in:
ThorstenB 2013-10-14 22:13:31 +02:00
parent e0c97199e6
commit 7ce2107336
5 changed files with 306 additions and 0 deletions

View file

@ -49,6 +49,7 @@
#include <Network/AV400WSim.hxx>
#include <Network/garmin.hxx>
#include <Network/httpd.hxx>
#include <Network/igc.hxx>
#ifdef FG_JPEG_SERVER
# include <Network/jpg-httpd.hxx>
#endif
@ -147,6 +148,9 @@ FGIO::parse_port_config( const string& config )
} else if ( protocol == "garmin" ) {
FGGarmin *garmin = new FGGarmin;
io = garmin;
} else if ( protocol == "igc" ) {
IGCProtocol *igc = new IGCProtocol;
io = igc;
} else if ( protocol == "httpd" ) {
// determine port
string port = tokens[1];

View file

@ -1458,6 +1458,7 @@ struct OptionDesc {
{"AV400WSimA", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"AV400WSimB", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"garmin", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"igc", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"nmea", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"generic", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"props", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },

View file

@ -12,6 +12,7 @@ set(SOURCES
generic.cxx
httpd.cxx
HTTPClient.cxx
igc.cxx
joyclient.cxx
jsclient.cxx
lfsglass.cxx
@ -40,6 +41,7 @@ set(HEADERS
generic.hxx
httpd.hxx
HTTPClient.hxx
igc.hxx
joyclient.hxx
jsclient.hxx
lfsglass.hxx

243
src/Network/igc.cxx Normal file
View file

@ -0,0 +1,243 @@
// igc.cxx -- International Glider Commission (IGC) protocol class
//
// Written by Thorsten Brehm, started October 2013.
//
// Copyright (C) 2013 Thorsten Brehm - brehmt (at) gmail com
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
///////////////////////////////////////////////////////////////////////////////
/* Usage:
* "fgfs --igc=file,out,1,OutputFile.igc"
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
# include <Include/version.h>
#else
# include <Include/no_version.h>
#endif
#include <stdio.h> // sprintf
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/io/iochannel.hxx>
#include <simgear/timing/sg_time.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include "igc.hxx"
IGCProtocol::IGCProtocol() :
length(0)
{
}
IGCProtocol::~IGCProtocol()
{
}
// generate IGC header records
bool IGCProtocol::gen_Hrecords()
{
const char* AircraftType = fgGetString("/sim/aircraft", "unknown");;
const char* Callsign = fgGetString("/sim/multiplay/callsign", "");
SGTime *t = globals->get_time_params();
int Day = t->getGmt()->tm_mday;
int Month = t->getGmt()->tm_mon+1;
int Year = t->getGmt()->tm_year % 100;
#ifdef FLIGHTGEAR_VERSION
const char* Version = FLIGHTGEAR_VERSION;
#else
const char* Version = "unknown version";
#endif
length = snprintf(buf, FG_MAX_MSG_SIZE,
"HFDTE%02d%02d%02d\r\n" // date: DDMMYY
"HFFXA001\r\n" // fix accuracy (1 meter)
"HFGTYGliderType:%s\r\n" // aircraft type
"HFGIDGliderID:%s\r\n" // callsign
"HFDTM100GPSDatum:WGS84\r\n" // GPS datum type
"HFRFWFirmwareVersion:FlightGear %s\r\n" // "firmware" version
"HFRHWHardwareVersion:FlightGear Flight Simulator\r\n" // "hardware" version
"HFFTYFRType:Flight Simulator\r\n", // logger type
Day, Month, Year,
AircraftType,
Callsign,
Version);
SGIOChannel *io = get_io_channel();
io->write(buf, length);
return true;
}
// generate igc B record message
bool IGCProtocol::gen_message()
{
/* IGC B-record spec:
* B H H M M S S D D M MM MM N D D D M MM MM E V P P P P P G G G G G CR LF
*
* Description Size Element Remarks
* ------------------------------------------------------------------------------------------------------------------------------------------------
* Time UTC 6 bytes HHMMSS Valid characters 0-9. When a valid GNSS fix is received, the UTC time
* in a B-record line must be obtained directly from the same GNSS data
* package that was the source of the Lat/long and GNSS altitude that is
* recorded in the same B-record line. Other sources for the time in a
* B-record line (such as the Real-Time Clock in the recorder) must only
* be used to provide time-continuity where GNSS fixes are not available.
* Latitude 8 bytes DDMMmmmN/S Valid characters N, S, 0-9. Obtained directly from the same GPS data
* package that was the source of the UTC time that is recorded in the
* same B-record line. If no latitude is obtained from satellite data,
* pressure altitude fixing must continue, using times from the RTC.
* In this case, in B record lines must repeat the last latitude that was
* obtained from satellite data, until GPS fixing is regained.
* Longitude 9 bytes DDDMMmmmE/W Valid characters E,W, 0-9. Obtained directly from the same GPS data
* package that was the source of UTC time that is recorded in the same
* B-record line. If no longitude is obtained from satellite data,
* pressure altitude fixing must continue, using times from the RTC.
* In this case, in B record lines must repeat the last longitude
* that was obtained from satellite data, until GPS fixing is regained.
* Fix validity 1 byte. A or V Use A for a 3D fix and V for a 2D fix (no GPS altitude) or for no
* GPS data (pressure altitude data must continue to be recorded using
* times from the RTC).
* Press Alt. 5 bytes PPPPP Altitude to the ICAO ISA above the 1013.25 hPa sea level datum, valid
* characters 0-9 and negative sign "-". Negative values to have negative
* sign instead of leading zero.
* GNSS Alt. 5 bytes GGGGG Altitude above the WGS84 ellipsoid, valid characters 0-9.
*/
char lonDir = 'E', latDir = 'N';
int lonDeg, latDeg, lonMin, latMin;
SGTime *t = globals->get_time_params();
double deg = fdm.get_Latitude() * SGD_RADIANS_TO_DEGREES;
if (deg < 0.0)
{
deg = -deg;
latDir = 'S';
}
latDeg = (int)(deg);
latMin = (int)((deg - (double)latDeg) * 60.0 * 1000.0);
deg = fdm.get_Longitude() * SGD_RADIANS_TO_DEGREES;
if (deg < 0.0)
{
deg = -deg;
lonDir = 'W';
}
lonDeg = (int)(deg);
lonMin = (int)((deg - (double)lonDeg) * 60.0 * 1000.0);
int Altitude = fdm.get_Altitude() * SG_FEET_TO_METER;
if (Altitude < 0)
Altitude = 0;
int h = t->getGmt()->tm_hour;
int m = t->getGmt()->tm_min;
int s = t->getGmt()->tm_sec;
// write the B record
length = snprintf(buf,FG_MAX_MSG_SIZE,
"B"
"%02d%02d%02d" // UTC time: HHMMSS
"%02d%05d%c" // Latitude: DDMMmmmN (or ..S)
"%03d%05d%c" // Longitude: DDDMMmmmE (or ..W)
"A" // Fix validity: A for a 3D fix, V for 2D fix
"%05d" // Pressure Altitude: PPPPP (above 1013.2 hPa)
"%05d" // GNSS Altitude: AAAAA
"\r\n", // Line feed: CR LF
h, m, s,
latDeg, latMin, latDir,
lonDeg, lonMin, lonDir,
Altitude, // This should be standard pressure altitude instead. Hm, well :).
Altitude // GPS altitude
);
return (length > 0);
}
// reading IGC files is not supported
bool IGCProtocol::parse_message()
{
return false;
}
// write header data
bool IGCProtocol::open()
{
if ( is_enabled() )
{
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
<< "is already in use, ignoring" );
return false;
}
SGIOChannel *io = get_io_channel();
if (!io->open( get_direction() ))
{
SG_LOG( SG_IO, SG_ALERT, "Error opening channel communication layer." );
return false;
}
set_enabled( true );
gen_Hrecords();
return true;
}
// process work
bool IGCProtocol::process()
{
SGIOChannel *io = get_io_channel();
if ( get_direction() == SG_IO_OUT )
{
gen_message();
if (!io->write( buf, length ))
{
SG_LOG( SG_IO, SG_WARN, "Error writing data." );
return false;
}
} else
if ( get_direction() == SG_IO_IN )
{
SG_LOG( SG_IO, SG_ALERT, "Error: IGC input is not supported.");
return false;
}
return true;
}
// close the channel
bool IGCProtocol::close()
{
SGIOChannel *io = get_io_channel();
set_enabled(false);
return io->close();
}

56
src/Network/igc.hxx Normal file
View file

@ -0,0 +1,56 @@
// igc.hxx -- International Glider Commission (IGC) protocol class
//
// Written by Thorsten Brehm, started October 2013.
//
// Copyright (C) 2013 Thorsten Brehm - brehmt (at) gmail com
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _FG_IGC_HXX
#define _FG_IGC_HXX
#include <simgear/compiler.h>
#include <FDM/flightProperties.hxx>
#include "protocol.hxx"
class IGCProtocol : public FGProtocol
{
char buf[FG_MAX_MSG_SIZE];
int length;
bool gen_Hrecords();
public:
IGCProtocol();
~IGCProtocol();
bool gen_message();
bool parse_message();
// open hailing frequencies
bool open();
// process work for this port
bool process();
// close the channel
bool close();
FlightProperties fdm;
};
#endif // _FG_IGC_HXX