4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "IGC/IGCWriter.hpp"
25 #include "IGCString.hpp"
26 #include "NMEA/Info.hpp"
27 #include "Version.hpp"
30 #include <windef.h> /* for MAX_PATH */
33 FormatIGCLocation(char *buffer
, const GeoPoint
&location
)
35 char latitude_suffix
= negative(location
.latitude
.Native())
38 (unsigned)uround(fabs(location
.latitude
.Degrees() * 60000));
40 char longitude_suffix
= negative(location
.longitude
.Native())
43 (unsigned)uround(fabs(location
.longitude
.Degrees() * 60000));
45 sprintf(buffer
, "%02u%05u%c%03u%05u%c",
46 latitude
/ 60000, latitude
% 60000, latitude_suffix
,
47 longitude
/ 60000, longitude
% 60000, longitude_suffix
);
49 return buffer
+ strlen(buffer
);
52 IGCWriter::IGCWriter(const TCHAR
*path
)
61 IGCWriter::CommitLine(char *line
)
63 if (!file
.WriteLine(line
))
66 grecord
.AppendRecordToBuffer(line
);
71 IGCWriter::WriteLine(const char *line
)
73 assert(strchr(line
, '\r') == NULL
);
74 assert(strchr(line
, '\n') == NULL
);
76 char *const dest
= BeginLine();
80 char *const end
= dest
+ MAX_IGC_BUFF
- 1, *p
= dest
;
82 p
= CopyIGCString(dest
, end
, line
);
85 return CommitLine(dest
);
89 IGCWriter::WriteLine(const char *a
, const TCHAR
*b
)
91 size_t a_length
= strlen(a
);
92 assert(a_length
< MAX_IGC_BUFF
);
94 char *const dest
= BeginLine();
98 char *const end
= dest
+ MAX_IGC_BUFF
- 1, *p
= dest
;
100 p
= std::copy(a
, a
+ a_length
, p
);
101 p
= CopyIGCString(p
, end
, b
);
104 return CommitLine(dest
);
108 IGCWriter::WriteHeader(const BrokenDateTime
&date_time
,
109 const TCHAR
*pilot_name
, const TCHAR
*aircraft_model
,
110 const TCHAR
*aircraft_registration
,
111 const TCHAR
*competition_id
,
112 const char *logger_id
, const TCHAR
*driver_name
,
116 * HFDTE141203 <- should be UTC, same as time in filename
118 * HFPLTPILOT:JOHN WHARINGTON
119 * HFGTYGLIDERTYPE:LS 3
120 * HFGIDGLIDERID:VH-WUE
121 * HFDTM100GPSDATUM:WGS84
122 * HFRFWFIRMWAREVERSION:3.6
123 * HFRHWHARDWAREVERSION:3.4
124 * HFFTYFR TYPE:GARRECHT INGENIEURGESELLSCHAFT,VOLKSLOGGER 1.0
125 * HFCIDCOMPETITIONID:WUE
126 * HFCCLCOMPETITIONCLASS:FAI
129 assert(date_time
.Plausible());
130 assert(logger_id
!= NULL
);
131 assert(strlen(logger_id
) == 3);
135 // Flight recorder ID number MUST go first..
136 sprintf(buffer
, "AXCS%s", logger_id
);
139 sprintf(buffer
, "HFDTE%02u%02u%02u",
140 date_time
.day
, date_time
.month
, date_time
.year
% 100);
144 WriteLine(GetHFFXARecord());
146 WriteLine("HFPLTPILOT:", pilot_name
);
147 WriteLine("HFGTYGLIDERTYPE:", aircraft_model
);
148 WriteLine("HFGIDGLIDERID:", aircraft_registration
);
149 WriteLine("HFCIDCOMPETITIONID:", competition_id
);
150 WriteLine("HFFTYFRTYPE:XCSOAR,XCSOAR ", XCSoar_VersionStringOld
);
151 WriteLine("HFGPS:", driver_name
);
153 WriteLine("HFDTM100DATUM:WGS-84");
155 WriteLine(GetIRecord());
159 IGCWriter::StartDeclaration(const BrokenDateTime
&date_time
,
160 const int number_of_turnpoints
)
162 assert(date_time
.Plausible());
164 // IGC GNSS specification 3.6.1
166 sprintf(buffer
, "C%02u%02u%02u%02u%02u%02u0000000000%02d",
167 // DD MM YY HH MM SS DD MM YY IIII TT
170 date_time
.year
% 100,
174 number_of_turnpoints
- 2);
179 // IGC GNSS specification 3.6.3
180 WriteLine("C0000000N00000000ETAKEOFF");
184 IGCWriter::EndDeclaration()
186 // TODO bug: this is causing problems with some analysis software
187 // maybe it's because the date and location fields are bogus
188 WriteLine("C0000000N00000000ELANDING");
192 IGCWriter::AddDeclaration(const GeoPoint
&location
, const TCHAR
*id
)
198 p
= FormatIGCLocation(p
, location
);
199 CopyASCIIUppper(p
, id
);
205 IGCWriter::LoggerNote(const TCHAR
*text
)
207 WriteLine("LPLT", text
);
211 * Applies range checks to the specified altitude value and converts
212 * it to an integer suitable for printing in the IGC file.
215 NormalizeIGCAltitude(int value
)
218 /* for negative values, there are only 4 characters left (after
219 the minus sign), and besides that, IGC does not support a
220 journey towards the center of the earth */
224 /* hooray, new world record! .. or just some invalid value; we
225 have only 5 characters for the altitude, so we must clip it at
233 IGCWriter::LogPoint(const IGCFix
&fix
, int epe
, int satellites
)
238 sprintf(p
, "B%02d%02d%02d", fix
.time
.hour
, fix
.time
.minute
, fix
.time
.second
);
241 p
= FormatIGCLocation(p
, fix
.location
);
243 sprintf(p
, "%c%05d%05d%03d%02d",
244 fix
.gps_valid
? 'A' : 'V',
245 NormalizeIGCAltitude(fix
.pressure_altitude
),
246 NormalizeIGCAltitude(fix
.gps_altitude
),
254 IGCWriter::LogPoint(const NMEAInfo
& gps_info
)
256 if (fix
.Apply(gps_info
))
257 LogPoint(fix
, (int)GetEPE(gps_info
.gps
), GetSIU(gps_info
.gps
));
261 IGCWriter::LogEvent(const BrokenTime
&time
, const char *event
)
264 sprintf(e_record
, "E%02d%02d%02d%s",
265 time
.hour
, time
.minute
, time
.second
, event
);
271 IGCWriter::LogEvent(const IGCFix
&fix
, int epe
, int satellites
,
274 LogEvent(fix
.time
, event
);
276 // tech_spec_gnss.pdf says we need a B record immediately after an E record
277 LogPoint(fix
, epe
, satellites
);
281 IGCWriter::LogEvent(const NMEAInfo
&gps_info
, const char *event
)
283 LogEvent(gps_info
.date_time_utc
, event
);
285 // tech_spec_gnss.pdf says we need a B record immediately after an E record
290 IGCWriter::LogEmptyFRecord(const BrokenTime
&time
)
293 sprintf(f_record
, "F%02u%02u%02u", time
.hour
, time
.minute
, time
.second
);
298 IGCWriter::LogFRecord(const BrokenTime
&time
, const int *satellite_ids
)
301 sprintf(f_record
, "F%02u%02u%02u", time
.hour
, time
.minute
, time
.second
);
303 for (unsigned i
= 0, length
= 7; i
< GPSState::MAXSATELLITES
; ++i
) {
304 if (satellite_ids
[i
] > 0) {
305 sprintf(f_record
+ length
, "%02d", satellite_ids
[i
]);
316 assert(file
.IsOpen());
318 grecord
.FinalizeBuffer();
319 grecord
.WriteTo(file
);