]> git.mxchange.org Git - flightgear.git/blob - src/Network/igc.cxx
New PathsDialog, for managing locations.
[flightgear.git] / src / Network / igc.cxx
1 // igc.cxx -- International Glider Commission (IGC) protocol class
2 //
3 // Written by Thorsten Brehm, started October 2013.
4 //
5 // Copyright (C) 2013 Thorsten Brehm - brehmt (at) gmail com
6 //
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.
11 //
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.
16 //
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.
20 //
21 ///////////////////////////////////////////////////////////////////////////////
22
23 /* Usage:
24  *  "fgfs --igc=file,out,1,OutputFile.igc"
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #  include "config.h"
29 #endif
30
31 #include <Include/version.h>
32
33 #include <stdio.h>  // sprintf
34 #include <simgear/debug/logstream.hxx>
35 #include <simgear/math/sg_geodesy.hxx>
36 #include <simgear/io/iochannel.hxx>
37 #include <simgear/timing/sg_time.hxx>
38
39 #include <Main/fg_props.hxx>
40 #include <Main/globals.hxx>
41
42 #include "igc.hxx"
43
44 IGCProtocol::IGCProtocol() :
45     length(0)
46 {
47 }
48
49 IGCProtocol::~IGCProtocol()
50 {
51 }
52
53 // generate IGC header records
54 bool IGCProtocol::gen_Hrecords()
55 {
56     const char* AircraftType = fgGetString("/sim/aircraft", "unknown");;
57     const char* Callsign     = fgGetString("/sim/multiplay/callsign", "");
58
59     SGTime *t = globals->get_time_params();
60     int Day   = t->getGmt()->tm_mday;
61     int Month = t->getGmt()->tm_mon+1;
62     int Year  = t->getGmt()->tm_year % 100;
63
64 #ifdef FLIGHTGEAR_VERSION
65     const char* Version = FLIGHTGEAR_VERSION;
66 #else
67     const char* Version = "unknown version";
68 #endif
69
70     length = snprintf(buf, FG_MAX_MSG_SIZE,
71                     "HFDTE%02d%02d%02d\r\n"         // date: DDMMYY
72                     "HFFXA001\r\n"                  // fix accuracy (1 meter)
73                     "HFGTYGliderType:%s\r\n"        // aircraft type
74                     "HFGIDGliderID:%s\r\n"          // callsign
75                     "HFDTM100GPSDatum:WGS84\r\n"    // GPS datum type
76                     "HFRFWFirmwareVersion:FlightGear %s\r\n" // "firmware" version
77                     "HFRHWHardwareVersion:FlightGear Flight Simulator\r\n" // "hardware" version
78                     "HFFTYFRType:Flight Simulator\r\n", // logger type
79                     Day, Month, Year,
80                     AircraftType,
81                     Callsign,
82                     Version);
83     SGIOChannel *io = get_io_channel();
84     io->write(buf, length);
85
86     return true;
87 }
88
89 // generate igc B record message
90 bool IGCProtocol::gen_message()
91 {
92
93     /* IGC B-record spec:
94      *  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
95      *
96      *  Description     Size    Element     Remarks
97      *  ------------------------------------------------------------------------------------------------------------------------------------------------
98      *  Time UTC        6 bytes HHMMSS      Valid characters 0-9. When a valid GNSS fix is received, the UTC time
99      *                                      in a B-record line must be obtained directly from the same GNSS data
100      *                                      package that was the source of the Lat/long and GNSS altitude that is
101      *                                      recorded in the same B-record line. Other sources for the time in a
102      *                                      B-record line (such as the Real-Time Clock in the recorder) must only
103      *                                      be used to provide time-continuity where GNSS fixes are not available.
104      *  Latitude        8 bytes DDMMmmmN/S  Valid characters N, S, 0-9. Obtained directly from the same GPS data
105      *                                      package that was the source of the UTC time that is recorded in the
106      *                                      same B-record line. If no latitude is obtained from satellite data,
107      *                                      pressure altitude fixing must continue, using times from the RTC.
108      *                                      In this case, in B record lines must repeat the last latitude that was
109      *                                      obtained from satellite data, until GPS fixing is regained.
110      *  Longitude       9 bytes DDDMMmmmE/W Valid characters E,W, 0-9. Obtained directly from the same GPS data
111      *                                      package that was the source of UTC time that is recorded in the same
112      *                                      B-record line. If no longitude is obtained from satellite data,
113      *                                      pressure altitude fixing must continue, using times from the RTC.
114      *                                      In this case, in B record lines must repeat the last longitude
115      *                                      that was obtained from satellite data, until GPS fixing is regained.
116      *  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
117      *                                      GPS data (pressure altitude data must continue to be recorded using
118      *                                      times from the RTC).
119      *  Press Alt.      5 bytes PPPPP       Altitude to the ICAO ISA above the 1013.25 hPa sea level datum, valid
120      *                                      characters 0-9 and negative sign "-". Negative values to have negative
121      *                                      sign instead of leading zero.
122      *  GNSS Alt.       5 bytes GGGGG       Altitude above the WGS84 ellipsoid, valid characters 0-9.
123      */
124
125      char lonDir = 'E', latDir = 'N';
126      int lonDeg, latDeg, lonMin, latMin;
127
128      SGTime *t = globals->get_time_params();
129
130      double deg = fdm.get_Latitude() * SGD_RADIANS_TO_DEGREES;
131      if (deg < 0.0)
132      {
133          deg = -deg;
134          latDir = 'S';
135      }
136
137      latDeg = (int)(deg);
138      latMin = (int)((deg - (double)latDeg) * 60.0 * 1000.0);
139
140      deg = fdm.get_Longitude() * SGD_RADIANS_TO_DEGREES;
141      if (deg < 0.0)
142      {
143          deg = -deg;
144          lonDir = 'W';
145      }
146
147      lonDeg = (int)(deg);
148      lonMin = (int)((deg - (double)lonDeg) * 60.0 * 1000.0);
149
150      int Altitude = fdm.get_Altitude() * SG_FEET_TO_METER;
151      if (Altitude < 0)
152          Altitude = 0;
153
154      int h = t->getGmt()->tm_hour;
155      int m = t->getGmt()->tm_min;
156      int s = t->getGmt()->tm_sec;
157
158      // write the B record
159      length = snprintf(buf,FG_MAX_MSG_SIZE,
160                   "B"
161                   "%02d%02d%02d" // UTC time:           HHMMSS
162                   "%02d%05d%c"   // Latitude:           DDMMmmmN (or ..S)
163                   "%03d%05d%c"   // Longitude:          DDDMMmmmE (or ..W)
164                   "A"            // Fix validity:       A for a 3D fix, V for 2D fix
165                   "%05d"         // Pressure Altitude:  PPPPP (above 1013.2 hPa)
166                   "%05d"         // GNSS Altitude:      AAAAA
167                   "\r\n",        // Line feed:          CR LF
168                   h, m, s,
169                   latDeg, latMin, latDir,
170                   lonDeg, lonMin, lonDir,
171                   Altitude, // This should be standard pressure altitude instead. Hm, well :).
172                   Altitude  // GPS altitude
173              );
174
175      return (length > 0);
176 }
177
178 // reading IGC files is not supported
179 bool IGCProtocol::parse_message()
180 {
181     return false;
182 }
183
184 // write header data
185 bool IGCProtocol::open()
186 {
187     if ( is_enabled() )
188     {
189         SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
190                 << "is already in use, ignoring" );
191         return false;
192     }
193
194     SGIOChannel *io = get_io_channel();
195
196     if (!io->open( get_direction() ))
197     {
198         SG_LOG( SG_IO, SG_ALERT, "Error opening channel communication layer." );
199         return false;
200     }
201
202     set_enabled( true );
203
204     gen_Hrecords();
205
206     return true;
207 }
208
209 // process work
210 bool IGCProtocol::process()
211 {
212     SGIOChannel *io = get_io_channel();
213     if ( get_direction() == SG_IO_OUT )
214     {
215         gen_message();
216         if (!io->write( buf, length ))
217         {
218             SG_LOG( SG_IO, SG_WARN, "Error writing data." );
219             return false;
220         }
221     } else
222     if ( get_direction() == SG_IO_IN )
223     {
224         SG_LOG( SG_IO, SG_ALERT, "Error: IGC input is not supported.");
225         return false;
226     }
227
228     return true;
229 }
230
231 // close the channel
232 bool IGCProtocol::close()
233 {
234     SGIOChannel *io = get_io_channel();
235
236     set_enabled(false);
237
238     return io->close();
239 }