1 // igc.cxx -- International Glider Commission (IGC) protocol class
3 // Written by Thorsten Brehm, started October 2013.
5 // Copyright (C) 2013 Thorsten Brehm - brehmt (at) gmail com
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
21 ///////////////////////////////////////////////////////////////////////////////
24 * "fgfs --igc=file,out,1,OutputFile.igc"
31 #if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
32 # include <Include/version.h>
34 # include <Include/no_version.h>
37 #include <stdio.h> // sprintf
38 #include <simgear/debug/logstream.hxx>
39 #include <simgear/math/sg_geodesy.hxx>
40 #include <simgear/io/iochannel.hxx>
41 #include <simgear/timing/sg_time.hxx>
43 #include <Main/fg_props.hxx>
44 #include <Main/globals.hxx>
48 IGCProtocol::IGCProtocol() :
53 IGCProtocol::~IGCProtocol()
57 // generate IGC header records
58 bool IGCProtocol::gen_Hrecords()
60 const char* AircraftType = fgGetString("/sim/aircraft", "unknown");;
61 const char* Callsign = fgGetString("/sim/multiplay/callsign", "");
63 SGTime *t = globals->get_time_params();
64 int Day = t->getGmt()->tm_mday;
65 int Month = t->getGmt()->tm_mon+1;
66 int Year = t->getGmt()->tm_year % 100;
68 #ifdef FLIGHTGEAR_VERSION
69 const char* Version = FLIGHTGEAR_VERSION;
71 const char* Version = "unknown version";
74 length = snprintf(buf, FG_MAX_MSG_SIZE,
75 "HFDTE%02d%02d%02d\r\n" // date: DDMMYY
76 "HFFXA001\r\n" // fix accuracy (1 meter)
77 "HFGTYGliderType:%s\r\n" // aircraft type
78 "HFGIDGliderID:%s\r\n" // callsign
79 "HFDTM100GPSDatum:WGS84\r\n" // GPS datum type
80 "HFRFWFirmwareVersion:FlightGear %s\r\n" // "firmware" version
81 "HFRHWHardwareVersion:FlightGear Flight Simulator\r\n" // "hardware" version
82 "HFFTYFRType:Flight Simulator\r\n", // logger type
87 SGIOChannel *io = get_io_channel();
88 io->write(buf, length);
93 // generate igc B record message
94 bool IGCProtocol::gen_message()
98 * 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
100 * Description Size Element Remarks
101 * ------------------------------------------------------------------------------------------------------------------------------------------------
102 * Time UTC 6 bytes HHMMSS Valid characters 0-9. When a valid GNSS fix is received, the UTC time
103 * in a B-record line must be obtained directly from the same GNSS data
104 * package that was the source of the Lat/long and GNSS altitude that is
105 * recorded in the same B-record line. Other sources for the time in a
106 * B-record line (such as the Real-Time Clock in the recorder) must only
107 * be used to provide time-continuity where GNSS fixes are not available.
108 * Latitude 8 bytes DDMMmmmN/S Valid characters N, S, 0-9. Obtained directly from the same GPS data
109 * package that was the source of the UTC time that is recorded in the
110 * same B-record line. If no latitude is obtained from satellite data,
111 * pressure altitude fixing must continue, using times from the RTC.
112 * In this case, in B record lines must repeat the last latitude that was
113 * obtained from satellite data, until GPS fixing is regained.
114 * Longitude 9 bytes DDDMMmmmE/W Valid characters E,W, 0-9. Obtained directly from the same GPS data
115 * package that was the source of UTC time that is recorded in the same
116 * B-record line. If no longitude is obtained from satellite data,
117 * pressure altitude fixing must continue, using times from the RTC.
118 * In this case, in B record lines must repeat the last longitude
119 * that was obtained from satellite data, until GPS fixing is regained.
120 * 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
121 * GPS data (pressure altitude data must continue to be recorded using
122 * times from the RTC).
123 * Press Alt. 5 bytes PPPPP Altitude to the ICAO ISA above the 1013.25 hPa sea level datum, valid
124 * characters 0-9 and negative sign "-". Negative values to have negative
125 * sign instead of leading zero.
126 * GNSS Alt. 5 bytes GGGGG Altitude above the WGS84 ellipsoid, valid characters 0-9.
129 char lonDir = 'E', latDir = 'N';
130 int lonDeg, latDeg, lonMin, latMin;
132 SGTime *t = globals->get_time_params();
134 double deg = fdm.get_Latitude() * SGD_RADIANS_TO_DEGREES;
142 latMin = (int)((deg - (double)latDeg) * 60.0 * 1000.0);
144 deg = fdm.get_Longitude() * SGD_RADIANS_TO_DEGREES;
152 lonMin = (int)((deg - (double)lonDeg) * 60.0 * 1000.0);
154 int Altitude = fdm.get_Altitude() * SG_FEET_TO_METER;
158 int h = t->getGmt()->tm_hour;
159 int m = t->getGmt()->tm_min;
160 int s = t->getGmt()->tm_sec;
162 // write the B record
163 length = snprintf(buf,FG_MAX_MSG_SIZE,
165 "%02d%02d%02d" // UTC time: HHMMSS
166 "%02d%05d%c" // Latitude: DDMMmmmN (or ..S)
167 "%03d%05d%c" // Longitude: DDDMMmmmE (or ..W)
168 "A" // Fix validity: A for a 3D fix, V for 2D fix
169 "%05d" // Pressure Altitude: PPPPP (above 1013.2 hPa)
170 "%05d" // GNSS Altitude: AAAAA
171 "\r\n", // Line feed: CR LF
173 latDeg, latMin, latDir,
174 lonDeg, lonMin, lonDir,
175 Altitude, // This should be standard pressure altitude instead. Hm, well :).
176 Altitude // GPS altitude
182 // reading IGC files is not supported
183 bool IGCProtocol::parse_message()
189 bool IGCProtocol::open()
193 SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
194 << "is already in use, ignoring" );
198 SGIOChannel *io = get_io_channel();
200 if (!io->open( get_direction() ))
202 SG_LOG( SG_IO, SG_ALERT, "Error opening channel communication layer." );
214 bool IGCProtocol::process()
216 SGIOChannel *io = get_io_channel();
217 if ( get_direction() == SG_IO_OUT )
220 if (!io->write( buf, length ))
222 SG_LOG( SG_IO, SG_WARN, "Error writing data." );
226 if ( get_direction() == SG_IO_IN )
228 SG_LOG( SG_IO, SG_ALERT, "Error: IGC input is not supported.");
236 bool IGCProtocol::close()
238 SGIOChannel *io = get_io_channel();