1 /*
2 Enigma route and waypoint file format.
3 http://www.mglavionics.co.za/Docs/Enigma%20Waypoint%20format.pdf
4 Binary data are stored in little endian (Intel)
5
6 Copyright (C) 2009 Tobias Kretschmar, tobias.kretschmar@gmx.de
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
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.
17
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
22 */
23
24 #include "defs.h"
25 #include <cmath>
26 #include <cstdlib>
27
28 #define MYNAME "Enigma binary route and waypoint file format"
29
30 #define WTYPE_WAYPOINT 0 // Waypoint of unspecified type
31 #define WTYPE_AIRPORT 1 // Typical assignment for medium sized airports
32 #define WTYPE_MAJORAIRPORT 2 // Typical assignment for large and international airports
33 #define WTYPE_SEAPLANEBASE 3
34 #define WTYPE_AIRFIELD 4 // Typical assignment for smaller municipal airfields, glider fields etc
35 #define WTYPE_PRIVATEAIRFIELD 5
36 #define WTYPE_ULTRALIGHTFIELD 6
37 #define WTYPE_INTERSECTION 7 // (reporting point, boundary crossing)
38 #define WTYPE_HELIPORT 8
39 #define WTYPE_TACAN 9
40 #define WTYPE_NDBDME 10
41 #define WTYPE_NDB 11
42 #define WTYPE_VORDME 12
43 #define WTYPE_VORTAC 13
44 #define WTYPE_FANMARKER 14
45 #define WTYPE_VOR 15
46 #define WTYPE_REPPT 16
47 #define WTYPE_LFR 17
48 #define WTYPE_UHFNDB 18
49 #define WTYPE_MNDB 19
50 #define WTYPE_MNDBDME 20
51 #define WTYPE_LOM 21
52 #define WTYPE_LMM 22
53 #define WTYPE_LOCSDF 23
54 #define WTYPE_MLSISMLS 24
55 #define WTYPE_OTHERNAV 25 // Navaid not falling into any of the above types
56 #define WTYPE_ALTITUDECHANGE 26 // Location at which altitude should be changed
57
58 union wpt_data {
59 int32_t wp_altitude; // Waypoint type 0-6,8: waypoint altitude in feet
60 int32_t tg_altitude; // Waypoint type 26: target altitude in feet
61 uint32_t frequency; // Waypoint type 9-25: freq in steps of 1000Hz (118Mhz = 180000)
62 int32_t dummy; // waypoint type 7, unused
63 };
64
65 struct enigma_wpt {
66 int32_t latitude;
67 int32_t longitude;
68 union wpt_data data;
69 uint8_t waypoint_type;
70 uint8_t shortname_len; // number of used characters in shortname
71 char shortname[6]; // ASCII, unused characters are "don't care" values
72 uint8_t longname_len; // number of used characters in longname
73 char longname[27]; // ASCII, unused characters are "don't care" values
74 };
75
76 static gbfile* file_in, *file_out;
77
78 static void
rd_init(const QString & fname)79 rd_init(const QString& fname)
80 {
81 file_in = gbfopen_le(fname, "rb", MYNAME);
82 }
83
decToEnigmaPosition(double val)84 static int32_t decToEnigmaPosition(double val)
85 {
86 int degrees = fabs(val);
87 double frac = fabs(val) - degrees;
88 int enigmadeg = degrees * 180000;
89 int enigmafrac = 180000 * frac;
90 int sign = (val < 0) ? -1 : +1;
91 return sign * (enigmadeg + enigmafrac);
92 }
93
enigmaPositionToDec(int32_t val)94 static float enigmaPositionToDec(int32_t val)
95 {
96 int deg = abs(val) / 180000;
97 int enigmafrac = abs(val) % 180000;
98 double frac = (double)enigmafrac / 180000;
99 int sign = (val < 0) ? -1 : +1;
100 return sign * (deg + frac);
101 }
102
103 static void
data_read()104 data_read()
105 {
106 enigma_wpt ewpt;
107 auto* route = new route_head;
108 route_add_head(route);
109
110 while (1 == gbfread(&ewpt, sizeof(ewpt), 1, file_in)) {
111 auto* wpt = new Waypoint;
112 wpt->latitude = enigmaPositionToDec(le_read32(&ewpt.latitude));
113 wpt->longitude = enigmaPositionToDec(le_read32(&ewpt.longitude));
114 char*sn = xstrndup(ewpt.shortname, ewpt.shortname_len);
115 wpt->shortname = sn;
116 xfree(sn);
117
118 char* ds = xstrndup(ewpt.longname, ewpt.longname_len);
119 wpt->description = ds;
120 xfree(ds);
121
122 switch (ewpt.waypoint_type) {
123 case WTYPE_WAYPOINT: // 0
124 case WTYPE_AIRPORT: // 1
125 case WTYPE_MAJORAIRPORT: // 2
126 case WTYPE_SEAPLANEBASE: // 3
127 case WTYPE_AIRFIELD: // 4
128 case WTYPE_PRIVATEAIRFIELD: // 5
129 case WTYPE_ULTRALIGHTFIELD: // 6
130 case WTYPE_HELIPORT: // 8
131 // waypoint altitude
132 wpt->altitude = FEET_TO_METERS(le_read32(&ewpt.data.wp_altitude) - 1000);
133 break;
134 case WTYPE_ALTITUDECHANGE: // 26
135 // target altitude
136 wpt->altitude = FEET_TO_METERS(le_read32(&ewpt.data.tg_altitude) - 1000);
137 break;
138 case WTYPE_INTERSECTION: // 7
139 // unused
140 break;
141 default:
142 // frequency
143 // wpt->frequency = wpt.le_readu32(ewpt.data.frequency);
144 ;
145 }
146 route_add_wpt(route, wpt);
147 }
148 }
149
150 static void
rd_deinit()151 rd_deinit()
152 {
153 gbfclose(file_in);
154 }
155
156 static void
wr_init(const QString & fname)157 wr_init(const QString& fname)
158 {
159 file_out = gbfopen_le(fname, "wb", MYNAME);
160 }
161
162 #ifndef min
163 #define min(a,b) (((a) < (b)) ? (a) : (b))
164 #endif
165 #ifndef max
166 #define max(a,b) (((a) > (b)) ? (a) : (b))
167 #endif
168
169 static void
enigma_waypt_disp(const Waypoint * wpt)170 enigma_waypt_disp(const Waypoint* wpt)
171 {
172 enigma_wpt ewpt;
173
174 memset(&ewpt, 0, sizeof(ewpt));
175
176 le_write32(&ewpt.latitude, decToEnigmaPosition(wpt->latitude));
177 le_write32(&ewpt.longitude, decToEnigmaPosition(wpt->longitude));
178 ewpt.waypoint_type = WTYPE_WAYPOINT;
179 if (wpt->altitude != unknown_alt) {
180 le_write32(&ewpt.data.wp_altitude, METERS_TO_FEET(wpt->altitude) + 1000);
181 }
182 if (wpt->shortname != nullptr) {
183 ewpt.shortname_len = (uint8_t) min(6, strlen(CSTRc(wpt->shortname)));
184 memcpy(ewpt.shortname, CSTRc(wpt->shortname), ewpt.shortname_len);
185 }
186 if (wpt->description != nullptr) {
187 ewpt.longname_len = (uint8_t) min(27, strlen(CSTRc(wpt->description)));
188 memcpy(ewpt.longname, CSTRc(wpt->description), ewpt.longname_len);
189 }
190 gbfwrite(&ewpt, sizeof(ewpt), 1, file_out);
191 }
192
193 static void
data_write()194 data_write()
195 {
196 route_disp_all(nullptr, nullptr, enigma_waypt_disp);
197 }
198
199 static void
wr_deinit()200 wr_deinit()
201 {
202 gbfclose(file_out);
203 }
204
205 ff_vecs_t enigma_vecs = {
206 ff_type_file,
207 {
208 ff_cap_none, /* waypoints */
209 ff_cap_none, /* tracks */
210 (ff_cap)(ff_cap_read | ff_cap_write) /* routes */
211 },
212 rd_init,
213 wr_init,
214 rd_deinit,
215 wr_deinit,
216 data_read,
217 data_write,
218 nullptr,
219 nullptr,
220 CET_CHARSET_ASCII, 0, /* CET-REVIEW */
221 NULL_POS_OPS,
222 nullptr
223 };
224