1 /*
2 Read and write GPilotS files.
3
4 Copyright (C) 2003 Robert Lipe, robertlipe@usa.net
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
19
20 */
21
22 #include "defs.h"
23 #if PDBFMTS_ENABLED
24 #include "pdbfile.h"
25 #include "garmin_tables.h"
26
27 #define MYNAME "GPilotS"
28 #define MYWPT 0x57707473 /* Wpts */
29 #define MYTRK 0x54726b73 /* Trks */
30 #define MYRTE 0x57707473 /* Wpts */
31 #define MYCREATOR 0x4750696c /* GPil */
32
33
34 /*
35 * Structures grafted from http://www.cru.fr/perso/cc/GPilotS/
36 */
37
38
39 typedef struct {
40 long lat; /* latitude in semicircles */
41 long lon; /* longitude in semicircles */
42 }
43 Semicircle_Type;
44
45 typedef struct {
46 char ident[6]; /* identifier */
47 unsigned char lat[4]; /* position */
48 unsigned char lon[4]; /* position */
49 unsigned char unused[4]; /* should be set to zero */
50 char cmnt[40]; /* comment */
51 unsigned char smbl; /* symbol id */
52 unsigned char dspl; /* display option */
53 } D103_Wpt_Type;
54
55 typedef union {
56 float f;
57 unsigned int i;
58 } fi_t;
59
60 typedef struct { /* size */
61 unsigned char wpt_class; /* class (see below) 1 */
62 unsigned char color; /* color (see below) 1 */
63 unsigned char dspl; /* display options (see below) 1 */
64 unsigned char attr; /* attributes (see below) 1 */
65 unsigned char smbl[2]; /* waypoint symbol 2 */
66 unsigned char subclass[18]; /* subclass 18 */
67 unsigned char lat[4]; /* position */
68 unsigned char lon[4]; /* position */
69 float alt; /* altitude in meters 4 */
70 float dpth; /* depth in meters 4 */
71 float dist; /* proximity distance in meters 4 */
72 char state[2]; /* state 2 */
73 char cc[2]; /* country code 2 */
74 char varlenstrs[1]; /* start of variable length strings */
75 /* G_char ident[]; variable length string 1-51 */
76 /* G_char comment[]; waypoint user comment 1-51 */
77 /* G_char facility[]; facility name 1-31 */
78 /* G_char city[]; city name 1-25 */
79 /* G_char addr[]; address number 1-51 */
80 /* G_char cross_road[]; intersecting road label 1-51 */
81 }
82 D108_Wpt_Type;
83
84 typedef struct { /* structure de waypoint "interne" */
85 unsigned char ident[51]; /* identifier (50 + '0') */
86 Semicircle_Type posn; /* position (common to all Garmin types) */
87 unsigned char cmnt[51]; /* comment (50 + '0') */
88 float dst; /* proximity distance */
89 float alt; /* altitude */
90 int smbl; /* symbol id */
91 unsigned char dspl; /* display option */
92 unsigned char color; /* color */
93 }
94 Custom_Wpt_Type;
95
96 typedef struct { /* internal track header */
97 char name[256]; /* nom du groupe de trackpoints */
98 unsigned char dspl; /* display on the map ? */
99 unsigned char color; /* color */
100 unsigned char type; /* type of following track points */
101 unsigned char unused; /* type of following track points */
102 unsigned char number[2]; /* number of track points */
103 unsigned char latmin[4]; /* latitude min */
104 unsigned char latmax[4]; /* latitude max */
105 unsigned char lonmin[4]; /* longitude min */
106 unsigned char lonmax[4]; /* longitude max */
107 unsigned char unused2[2]; /* type of following track points */
108 }
109 Custom_Trk_Hdr_Type;
110
111 typedef struct {
112 unsigned char lat[4]; /* position */
113 unsigned char lon[4]; /* position */
114 unsigned char time[4];
115 unsigned char alt[4];
116 unsigned char new_trk;
117 unsigned char unused;
118 } Custom_Trk_Point_Type;
119
120 typedef struct { /* custom compact track point type */
121 unsigned char lat[4]; /* position */
122 unsigned char lon[4]; /* position */
123 unsigned char new_trk;
124 unsigned char unused;
125 } Compact_Trk_Point_Type; /* size : 10 bytes */
126
127 struct record {
128 struct {
129 unsigned char type;
130 unsigned short size;
131 unsigned int version;
132 } header;
133 union {
134 D103_Wpt_Type d103;
135 D108_Wpt_Type d108;
136 Custom_Wpt_Type CustWpt;
137 Custom_Trk_Hdr_Type CustTrkHdr;
138 #if LATER
139 Custom_Rte_Hdr_Type CustRteHdr;
140 #endif
141 } wpt;
142 };
143
144
145 static pdbfile* file_in, *file_out;
146 static const char* out_fname;
147 static int ct = 0;
148 static char* dbname = NULL;
149
150 static
151 arglist_t my_args[] = {
152 {"dbname", &dbname, "Database name", NULL, ARGTYPE_STRING, ARG_NOMINMAX},
153 ARG_TERMINATOR
154 };
155
156 static void
rd_init(const char * fname)157 rd_init(const char* fname)
158 {
159 file_in = pdb_open(fname, MYNAME);
160 }
161
162 static void
rd_deinit(void)163 rd_deinit(void)
164 {
165 pdb_close(file_in);
166 if (dbname) {
167 xfree(dbname);
168 dbname = NULL;
169 }
170 }
171
172 static void
wr_init(const char * fname)173 wr_init(const char* fname)
174 {
175 file_out = pdb_create(fname, MYNAME);
176 out_fname = fname;
177 }
178
179 static void
wr_deinit(void)180 wr_deinit(void)
181 {
182 pdb_close(file_out);
183 if (dbname) {
184 xfree(dbname);
185 dbname = NULL;
186 }
187 }
188
189 static void
data_read(void)190 data_read(void)
191 {
192 struct record* rec;
193 pdbrec_t* pdb_rec;
194 route_head* track_head = NULL;
195
196 if (file_in->creator != MYCREATOR) {
197 fatal(MYNAME ": Not a %s file.\n", MYNAME);
198 }
199
200 switch (file_in->type) {
201 case MYWPT:
202 /* blah */
203 break;
204 case MYTRK:
205 /* blah */
206 break;
207 default:
208 fatal(MYNAME ": Unknown file type 0x%x\n", (int) file_in->type);
209 }
210
211 for (pdb_rec = file_in->rec_list; pdb_rec; pdb_rec=pdb_rec->next) {
212 waypoint* wpt_tmp;
213 Custom_Trk_Point_Type* tp_cust;
214 Compact_Trk_Point_Type* tp_comp;
215 int lat;
216 int lon;
217 int sz;
218 fi_t fi;
219 int trk_num = 0;
220 int trk_seg_num = 1;
221 char trk_seg_num_buf[10];
222 char* trk_name = "";
223
224 wpt_tmp = waypt_new();
225
226 rec = (struct record*) pdb_rec->data;
227 switch (rec->header.type) {
228 /*
229 * G103Type
230 */
231 case 4:
232 wpt_tmp->shortname = xstrndupt(rec->wpt.d103.ident, sizeof(rec->wpt.d103.ident));
233 wpt_tmp->description = xstrndupt(rec->wpt.d103.cmnt, sizeof(rec->wpt.d103.cmnt));
234 /* This is odd. This is a Palm DB file,
235 * yet the data appears to be little endian,
236 * not appropriate the the actual Palm.
237 */
238 lon = le_read32(&rec->wpt.d103.lon);
239 lat = le_read32(&rec->wpt.d103.lat);
240 wpt_tmp->longitude = lon / 2147483648.0 * 180.0;
241 wpt_tmp->latitude = lat / 2147483648.0 * 180.0;
242 waypt_add(wpt_tmp);
243 break;
244 /*
245 * G108Type
246 */
247 case 9:
248 wpt_tmp->shortname = xstrndupt(rec->wpt.d108.varlenstrs, 50);
249 wpt_tmp->description = xstrndupt(rec->wpt.d108.varlenstrs + strlen(wpt_tmp->shortname) + 1, 50);
250 /* This is odd. This is a Palm DB file,
251 * yet the data appears to be little endian,
252 * not appropriate the the actual Palm.
253 */
254 lon = le_read32(&rec->wpt.d108.lon);
255 lat = le_read32(&rec->wpt.d108.lat);
256 wpt_tmp->longitude = lon / 2147483648.0 * 180.0;
257 wpt_tmp->latitude = lat / 2147483648.0 * 180.0;
258 fi.i = le_read32(&rec->wpt.d108.alt);
259 wpt_tmp->altitude = fi.f;
260 fi.i = le_read32(&rec->wpt.d108.dpth);
261 WAYPT_SET(wpt_tmp, depth, fi.f);
262 fi.i = le_read32(&rec->wpt.d108.dist);
263 WAYPT_SET(wpt_tmp, proximity, fi.f);
264 wpt_tmp->wpt_flags.icon_descr_is_dynamic = 0;
265 wpt_tmp->icon_descr = gt_find_desc_from_icon_number((rec->wpt.d108.smbl[1] << 8) + rec->wpt.d108.smbl[0], PCX, NULL);
266 waypt_add(wpt_tmp);
267 break;
268
269 /*
270 * CustomTrkHdr
271 */
272 case 101:
273 trk_name = rec->wpt.CustTrkHdr.name;
274 sz = be_read16(&rec->wpt.CustTrkHdr.number);
275
276 /* switch between custom track points and compact track points.
277 * (compact points have no altitude and time info.
278 */
279 switch (rec->wpt.CustTrkHdr.type) {
280 case 102:
281 tp_cust = (Custom_Trk_Point_Type*)((char*) pdb_rec->data + sizeof(rec->header) + sizeof(rec->wpt.CustTrkHdr));
282 while (sz--) {
283 if ((int)(tp_cust->new_trk) == 1 || trk_seg_num == 1) {
284 /*
285 * Start a new track segment
286 */
287 track_head = route_head_alloc();
288 if (trk_seg_num == 1) {
289 track_head->rte_name = xstrdup(trk_name);
290 } else {
291 /* name in the form TRACKNAME #n */
292 snprintf(trk_seg_num_buf, sizeof(trk_seg_num_buf), "%d", trk_seg_num);
293 track_head->rte_name = (char*) xmalloc(strlen(trk_name)+strlen(trk_seg_num_buf)+3);
294 sprintf(track_head->rte_name, "%s #%s", trk_name, trk_seg_num_buf);
295 }
296 trk_seg_num++;
297 track_head->rte_num = trk_num;
298 trk_num++;
299 track_add_head(track_head);
300 }
301
302 wpt_tmp = waypt_new();
303
304 /* This is even more odd.
305 * Track data is stored as big endian while
306 * waypoint data is little endian!?
307 */
308 lon = be_read32(&tp_cust->lon);
309 lat = be_read32(&tp_cust->lat);
310 wpt_tmp->longitude = lon / 2147483648.0 * 180.0;
311 wpt_tmp->latitude = lat / 2147483648.0 * 180.0;
312 /*
313 * Convert Garmin/GPilotS time format to gpsbabel time format.
314 * Garmin/GPilotS count seconds from "UTC 12:00 AM December 31 1989".
315 * gpsbabel counts seconds from "UTC 12:00 AM January 1 1970".
316 */
317 wpt_tmp->creation_time = be_read32(&tp_cust->time) + 631065600;
318 fi.i = be_read32(&tp_cust->alt);
319 wpt_tmp->altitude = fi.f;
320 track_add_wpt(track_head, wpt_tmp);
321 tp_cust++;
322 }
323 break;
324 case 104:
325 tp_comp = (Compact_Trk_Point_Type*)((char*) pdb_rec->data + sizeof(rec->header) + sizeof(rec->wpt.CustTrkHdr));
326 while (sz--) {
327 if ((int)(tp_comp->new_trk) == 1 || trk_seg_num == 1) {
328 /*
329 * Start a new track segment
330 */
331 track_head = route_head_alloc();
332 if (trk_seg_num == 1) {
333 track_head->rte_name = xstrdup(trk_name);
334 } else {
335 /* name in the form TRACKNAME #n */
336 snprintf(trk_seg_num_buf, sizeof(trk_seg_num_buf), "%d", trk_seg_num);
337 track_head->rte_name = (char*) xmalloc(strlen(trk_name)+strlen(trk_seg_num_buf)+3);
338 sprintf(track_head->rte_name, "%s #%s", trk_name, trk_seg_num_buf);
339 }
340 trk_seg_num++;
341 track_head->rte_num = trk_num;
342 trk_num++;
343 track_add_head(track_head);
344 }
345
346 wpt_tmp = waypt_new();
347 lon = be_read32(&tp_comp->lon);
348 lat = be_read32(&tp_comp->lat);
349 wpt_tmp->longitude = lon / 2147483648.0 * 180.0;
350 wpt_tmp->latitude = lat / 2147483648.0 * 180.0;
351 track_add_wpt(track_head, wpt_tmp);
352 tp_comp++;
353 }
354 break;
355 default:
356 fatal(MYNAME ": track point type %d not supported.\n", rec->wpt.CustTrkHdr.type);
357 }
358 break;
359 default:
360 fatal(MYNAME ": input record type %d not supported.\n", rec->header.type);
361 }
362
363 }
364 }
365
366
367 struct hdr {
368 char* wpt_name;
369 waypoint* wpt;
370 };
371
372 static void
my_write_wpt(const waypoint * wpt)373 my_write_wpt(const waypoint* wpt)
374 {
375 struct record* rec;
376 char* vdata;
377 int lat, lon;
378
379 rec = (struct record*) xcalloc(sizeof *rec, 1);
380 vdata = (char*)rec + sizeof(*rec);
381
382 rec->header.type = 4;
383 rec->header.size = 5;
384 rec->header.version = 6;
385
386 strncpy(rec->wpt.d103.ident, wpt->shortname, sizeof(rec->wpt.d103.ident));
387 strncpy(rec->wpt.d103.cmnt, wpt->description, sizeof(rec->wpt.d103.cmnt));
388 lat = wpt->latitude / 180.0 * 2147483648.0;
389 lon = wpt->longitude / 180.0 * 2147483648.0;
390 le_write32(&rec->wpt.d103.lat, lat);
391 le_write32(&rec->wpt.d103.lon, lon);
392
393 pdb_write_rec(file_out, 0, ct, ct+1, rec, (char*)vdata - (char*)rec);
394 ct++;
395 xfree(rec);
396 }
397
398 static void
data_write(void)399 data_write(void)
400 {
401 if (dbname) {
402 strncpy(file_out->name, dbname, PDB_DBNAMELEN);
403 } else {
404 strncpy(file_out->name, out_fname, PDB_DBNAMELEN);
405 }
406
407 /*
408 * Populate header.
409 */
410 file_out->name[PDB_DBNAMELEN-1] = 0;
411 file_out->attr = PDB_FLAG_BACKUP;
412 file_out->ctime = file_out->mtime = current_time() + 2082844800U;
413
414 file_out->type = MYWPT;
415 file_out->creator = MYCREATOR;
416 file_out->version = 1;
417
418 waypt_disp_all(my_write_wpt);
419 }
420
421
422 ff_vecs_t gpilots_vecs = {
423 ff_type_file,
424 { (ff_cap)(ff_cap_read | ff_cap_write), (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none},
425 rd_init,
426 wr_init,
427 rd_deinit,
428 wr_deinit,
429 data_read,
430 data_write,
431 NULL,
432 my_args,
433 CET_CHARSET_ASCII, 0 /* CET-REVIEW */
434 };
435 #endif
436