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:
parent
e0c97199e6
commit
7ce2107336
5 changed files with 306 additions and 0 deletions
|
@ -49,6 +49,7 @@
|
||||||
#include <Network/AV400WSim.hxx>
|
#include <Network/AV400WSim.hxx>
|
||||||
#include <Network/garmin.hxx>
|
#include <Network/garmin.hxx>
|
||||||
#include <Network/httpd.hxx>
|
#include <Network/httpd.hxx>
|
||||||
|
#include <Network/igc.hxx>
|
||||||
#ifdef FG_JPEG_SERVER
|
#ifdef FG_JPEG_SERVER
|
||||||
# include <Network/jpg-httpd.hxx>
|
# include <Network/jpg-httpd.hxx>
|
||||||
#endif
|
#endif
|
||||||
|
@ -147,6 +148,9 @@ FGIO::parse_port_config( const string& config )
|
||||||
} else if ( protocol == "garmin" ) {
|
} else if ( protocol == "garmin" ) {
|
||||||
FGGarmin *garmin = new FGGarmin;
|
FGGarmin *garmin = new FGGarmin;
|
||||||
io = garmin;
|
io = garmin;
|
||||||
|
} else if ( protocol == "igc" ) {
|
||||||
|
IGCProtocol *igc = new IGCProtocol;
|
||||||
|
io = igc;
|
||||||
} else if ( protocol == "httpd" ) {
|
} else if ( protocol == "httpd" ) {
|
||||||
// determine port
|
// determine port
|
||||||
string port = tokens[1];
|
string port = tokens[1];
|
||||||
|
|
|
@ -1458,6 +1458,7 @@ struct OptionDesc {
|
||||||
{"AV400WSimA", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
{"AV400WSimA", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
||||||
{"AV400WSimB", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
{"AV400WSimB", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
||||||
{"garmin", 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 },
|
{"nmea", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
||||||
{"generic", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
{"generic", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
||||||
{"props", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
{"props", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
|
||||||
|
|
|
@ -12,6 +12,7 @@ set(SOURCES
|
||||||
generic.cxx
|
generic.cxx
|
||||||
httpd.cxx
|
httpd.cxx
|
||||||
HTTPClient.cxx
|
HTTPClient.cxx
|
||||||
|
igc.cxx
|
||||||
joyclient.cxx
|
joyclient.cxx
|
||||||
jsclient.cxx
|
jsclient.cxx
|
||||||
lfsglass.cxx
|
lfsglass.cxx
|
||||||
|
@ -40,6 +41,7 @@ set(HEADERS
|
||||||
generic.hxx
|
generic.hxx
|
||||||
httpd.hxx
|
httpd.hxx
|
||||||
HTTPClient.hxx
|
HTTPClient.hxx
|
||||||
|
igc.hxx
|
||||||
joyclient.hxx
|
joyclient.hxx
|
||||||
jsclient.hxx
|
jsclient.hxx
|
||||||
lfsglass.hxx
|
lfsglass.hxx
|
||||||
|
|
243
src/Network/igc.cxx
Normal file
243
src/Network/igc.cxx
Normal 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
56
src/Network/igc.hxx
Normal 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
|
Loading…
Add table
Reference in a new issue