]> git.street.me.uk Git - andy/viking.git/blob - src/datasource_gps.c
Automatically remove suspicious first points of GPX Tracks.
[andy/viking.git] / src / datasource_gps.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2006, Alex Foobarian <foobarian@gmail.com>
6  * Copyright (C) 2012-2015, Rob Norris <rw_norris@hotmail.com>
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <string.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include <glib/gstdio.h>
32 #include <glib/gprintf.h>
33 #include <glib/gi18n.h>
34
35 #include "datasource_gps.h"
36 #include "viking.h"
37 #include "babel.h"
38 #include "gpx.h"
39 #include "acquire.h"
40
41 static gboolean gps_acquire_in_progress = FALSE;
42
43 static gint last_active = -1;
44
45 static gpointer datasource_gps_init_func ( acq_vik_t *avt );
46 static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 );
47 static void datasource_gps_cleanup ( gpointer user_data );
48 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
49 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
50 static void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data );
51 static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
52
53 VikDataSourceInterface vik_datasource_gps_interface = {
54   N_("Acquire from GPS"),
55   N_("Acquired from GPS"),
56   VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT,
57   VIK_DATASOURCE_INPUTTYPE_NONE,
58   TRUE,
59   TRUE,
60   TRUE,
61   (VikDataSourceInitFunc)               datasource_gps_init_func,
62   (VikDataSourceCheckExistenceFunc)     NULL,
63   (VikDataSourceAddSetupWidgetsFunc)    datasource_gps_add_setup_widgets,
64   (VikDataSourceGetProcessOptionsFunc)  datasource_gps_get_process_options,
65   (VikDataSourceProcessFunc)            a_babel_convert_from,
66   (VikDataSourceProgressFunc)           datasource_gps_progress,
67   (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
68   (VikDataSourceCleanupFunc)            datasource_gps_cleanup,
69   (VikDataSourceOffFunc)                datasource_gps_off,
70
71   NULL,
72   0,
73   NULL,
74   NULL,
75   0
76 };
77
78 /*********************************************************
79  * Definitions and routines for acquiring data from GPS
80  *********************************************************/
81
82 /* widgets in setup dialog specific to GPS */
83 /* widgets in progress dialog specific to GPS */
84 /* also counts needed for progress */
85 typedef struct {
86   /* setup dialog */
87   GtkWidget *proto_l;
88   GtkWidget *proto_b;
89   GtkWidget *ser_l;
90   GtkWidget *ser_b;
91   GtkWidget *off_request_l;
92   GtkCheckButton *off_request_b;
93   GtkWidget *get_tracks_l;
94   GtkCheckButton *get_tracks_b;
95   GtkWidget *get_routes_l;
96   GtkCheckButton *get_routes_b;
97   GtkWidget *get_waypoints_l;
98   GtkCheckButton *get_waypoints_b;
99
100   /* progress dialog */
101   GtkWidget *gps_label;
102   GtkWidget *wpt_label;
103   GtkWidget *trk_label;
104   GtkWidget *rte_label;
105   vik_gps_xfer_type progress_type;
106
107   // Maintain separate counts for each type
108   int wpt_total_count;
109   int wpt_count;
110   int trk_total_count;
111   int trk_count;
112   int rte_total_count;
113   int rte_count;
114   gchar *info;
115   // Know which way xfer is so xfer setting types are only stored for download
116   vik_gps_dir direction;
117   // GUI Updates
118   gint id_status;
119   gint id_info;
120   gint id_total_count;
121   gint id_count;
122 } gps_user_data_t;
123
124 #define VIK_SETTINGS_GPS_GET_TRACKS "gps_download_tracks"
125 #define VIK_SETTINGS_GPS_GET_ROUTES "gps_download_routes"
126 #define VIK_SETTINGS_GPS_GET_WAYPOINTS "gps_download_waypoints"
127 #define VIK_SETTINGS_GPS_PROTOCOL "gps_protocol"
128 #define VIK_SETTINGS_GPS_PORT "gps_port"
129 #define VIK_SETTINGS_GPS_POWER_OFF "gps_power_off"
130
131 static gpointer datasource_gps_init_func ( acq_vik_t *avt )
132 {
133   gps_user_data_t *gps_ud = g_malloc0 (sizeof(gps_user_data_t));
134   gps_ud->direction = GPS_DOWN;
135   return gps_ud;
136 }
137
138 /**
139  * datasource_gps_get_protocol:
140  *
141  * Method to get the communication protocol of the GPS device from the widget structure
142  */
143 gchar* datasource_gps_get_protocol ( gpointer user_data )
144 {
145   // Uses the list of supported devices
146   gps_user_data_t *w = (gps_user_data_t *)user_data;
147   last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
148   if (a_babel_device_list) {
149     gchar *protocol = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
150     a_settings_set_string ( VIK_SETTINGS_GPS_PROTOCOL, protocol );
151     return protocol;
152   }
153
154   return NULL;
155 }
156
157 /**
158  * datasource_gps_get_descriptor:
159  *
160  * Method to get the descriptor from the widget structure
161  * "Everything is a file"
162  * Could actually be normal file or a serial port
163  */
164 gchar* datasource_gps_get_descriptor ( gpointer user_data )
165 {
166   gps_user_data_t *w = (gps_user_data_t *)user_data;
167
168 #if GTK_CHECK_VERSION (2, 24, 0)
169   gchar *descriptor = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
170 #else
171   gchar *descriptor = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
172 #endif
173   a_settings_set_string ( VIK_SETTINGS_GPS_PORT, descriptor );
174   return descriptor;
175 }
176
177 /**
178  * datasource_gps_get_do_tracks:
179  *
180  * Method to get the track handling behaviour from the widget structure
181  */
182 gboolean datasource_gps_get_do_tracks ( gpointer user_data )
183 {
184   gps_user_data_t *w = (gps_user_data_t *)user_data;
185   gboolean get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
186   if ( w->direction == GPS_DOWN )
187     a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, get_tracks );
188   return get_tracks;
189 }
190
191 /**
192  * datasource_gps_get_do_routes:
193  *
194  * Method to get the route handling behaviour from the widget structure
195  */
196 gboolean datasource_gps_get_do_routes ( gpointer user_data )
197 {
198   gps_user_data_t *w = (gps_user_data_t *)user_data;
199   gboolean get_routes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_routes_b));
200   if ( w->direction == GPS_DOWN )
201     a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, get_routes );
202   return get_routes;
203 }
204
205 /**
206  * datasource_gps_get_do_waypoints:
207  *
208  * Method to get the waypoint handling behaviour from the widget structure
209  */
210 gboolean datasource_gps_get_do_waypoints ( gpointer user_data )
211 {
212   gps_user_data_t *w = (gps_user_data_t *)user_data;
213   gboolean get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
214   if ( w->direction == GPS_DOWN )
215     a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, get_waypoints );
216   return get_waypoints;
217 }
218
219 static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 )
220 {
221   char *device = NULL;
222   char *tracks = NULL;
223   char *routes = NULL;
224   char *waypoints = NULL;
225
226   if (gps_acquire_in_progress) {
227     po->babelargs = po->filename = NULL;
228   }
229   
230   gps_acquire_in_progress = TRUE;
231
232   device = datasource_gps_get_protocol ( user_data );
233
234   if ( datasource_gps_get_do_tracks ( user_data ) )
235     tracks = "-t";
236   else
237     tracks = "";
238
239   if ( datasource_gps_get_do_routes ( user_data ) )
240     routes = "-r";
241   else
242     routes = "";
243
244   if ( datasource_gps_get_do_waypoints ( user_data ) )
245     waypoints = "-w";
246   else
247     waypoints = "";
248
249   po->babelargs = g_strdup_printf("-D 9 %s %s %s -i %s", tracks, routes, waypoints, device);
250   /* device points to static content => no free */
251   device = NULL;
252   tracks = NULL;
253   routes = NULL;
254   waypoints = NULL;
255
256   po->filename = g_strdup(datasource_gps_get_descriptor(user_data));
257
258   g_debug(_("using cmd '%s' and file '%s'\n"), po->babelargs, po->filename);
259 }
260
261 /**
262  * datasource_gps_get_off:
263  *
264  * Method to get the off behaviour from the widget structure
265  */
266 gboolean datasource_gps_get_off ( gpointer user_data )
267 {
268   gps_user_data_t *w = (gps_user_data_t *)user_data;
269   gboolean power_off = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b));
270   a_settings_set_boolean ( VIK_SETTINGS_GPS_POWER_OFF, power_off );
271   return power_off;
272 }
273
274 static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **file_descriptor )
275 {
276   char *ser = NULL;
277   char *device = NULL;
278   gps_user_data_t *w = (gps_user_data_t *)user_data;
279
280   if (gps_acquire_in_progress) {
281     *babelargs = *file_descriptor = NULL;
282   }
283
284   /* See if we should turn off the device */
285   if (!datasource_gps_get_off ( user_data )){
286     return;
287   }
288   
289   if (!a_babel_device_list)
290     return;
291   last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
292   device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
293   if (!strcmp(device, "garmin")) {
294     device = "garmin,power_off";
295   }
296   else if (!strcmp(device, "navilink")) {
297     device = "navilink,power_off";
298   }
299   else {
300     return;
301   }
302
303   *babelargs = g_strdup_printf("-i %s", device);
304   /* device points to static content => no free */
305   device = NULL;
306   
307 #if GTK_CHECK_VERSION (2, 24, 0)
308   ser = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
309 #else
310   ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
311 #endif
312   *file_descriptor = g_strdup(ser);
313 }
314
315
316 static void datasource_gps_cleanup ( gpointer user_data )
317 {
318   gps_user_data_t *gud = (gps_user_data_t *)user_data;
319   // Remove any outstanding GUI update requests
320   if ( gud->id_status )
321     g_source_remove ( gud->id_status );
322   if ( gud->id_info )
323     g_source_remove ( gud->id_info );
324   if ( gud->id_total_count )
325     g_source_remove ( gud->id_total_count );
326   if ( gud->id_count )
327     g_source_remove ( gud->id_count );
328   g_free ( gud->info );
329   g_free ( gud );
330   gps_acquire_in_progress = FALSE;
331 }
332
333 /**
334  * datasource_gps_clean_up:
335  *
336  * External method to tidy up
337  */
338 void datasource_gps_clean_up ( gpointer user_data )
339 {
340   datasource_gps_cleanup ( user_data );
341 }
342
343 static gboolean show_total_count(acq_dialog_widgets_t *w)
344 {
345   gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
346   if (w->running) {
347     gint tmp_count;
348     GtkWidget *progress_label;
349     const gchar *tmp_str;
350     switch (gps_data->progress_type) {
351     case WPT:
352       progress_label = gps_data->wpt_label;
353       tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", gps_data->wpt_total_count);
354       tmp_count = gps_data->wpt_total_count;
355       break;
356     case TRK:
357       progress_label = gps_data->trk_label;
358       tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", gps_data->trk_total_count);
359       tmp_count = gps_data->trk_total_count;
360       break;
361     default:
362       progress_label = gps_data->rte_label;
363       tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", gps_data->rte_total_count);
364       tmp_count = gps_data->rte_total_count;
365       break;
366     }
367     gchar *s = g_strdup_printf(tmp_str, tmp_count);
368     gtk_label_set_text ( GTK_LABEL(progress_label), s );
369     gtk_widget_show ( progress_label );
370     g_free(s);
371   }
372   gps_data->id_total_count = 0;
373   return FALSE;
374 }
375
376 static gboolean show_current_count(acq_dialog_widgets_t *w)
377 {
378   gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
379   if (w->running) {
380     GtkWidget *progress_label;
381     gchar *s = NULL;
382     switch (gps_data->progress_type) {
383       case WPT:
384         progress_label = gps_data->wpt_label;
385         if ( gps_data->wpt_count < gps_data->wpt_total_count )
386           s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->wpt_count, gps_data->wpt_total_count, "waypoints");
387         else
388           s = g_strdup_printf(_("Downloaded %d %s."), gps_data->wpt_count, "waypoints");
389         break;
390       case TRK:
391         progress_label = gps_data->trk_label;
392         if ( gps_data->trk_count < gps_data->trk_total_count )
393           s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->trk_count, gps_data->trk_total_count, "trackpoints");
394         else
395           s = g_strdup_printf(_("Downloaded %d %s."), gps_data->trk_count, "trackpoints");
396         break;
397       default:
398         progress_label = gps_data->rte_label;
399         if ( gps_data->rte_count < gps_data->rte_total_count )
400           s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->rte_count, gps_data->rte_total_count, "routepoints");
401         else
402           s = g_strdup_printf(_("Downloaded %d %s."), gps_data->rte_count, "routepoints");
403         break;
404     }
405     gtk_label_set_text ( GTK_LABEL(progress_label), s );
406     g_free(s);
407   }
408   gps_data->id_count = 0;
409   return FALSE;
410 }
411
412 static gboolean show_gps_info(acq_dialog_widgets_t *w)
413 {
414   gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
415   if (w->running) {
416     gchar *s = g_strdup_printf ( _("GPS Device: %s"), gps_data->info );
417     gtk_label_set_text ( GTK_LABEL(gps_data->gps_label), s );
418     g_free(s);
419   }
420   gps_data->id_info = 0;
421   return FALSE;
422 }
423
424 static gboolean show_gps_status(acq_dialog_widgets_t *w)
425 {
426   gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
427   if (w->running) {
428     gtk_label_set_text ( GTK_LABEL(w->status), _("Status: Working...") );
429   }
430   gps_data->id_status = 0;
431   return FALSE;
432 }
433
434 /* 
435  * This routine relies on gpsbabel's diagnostic output to display the progress information. 
436  * These outputs differ when different GPS devices are used, so we will need to test
437  * them on several and add the corresponding support.
438  */
439 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
440 {
441   gchar *line;
442   gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
443
444   switch(c) {
445   case BABEL_DIAG_OUTPUT:
446     line = (gchar *)data;
447
448     gps_data->id_status = gdk_threads_add_idle ( (GSourceFunc)show_gps_status, w );
449
450     /* tells us the type of items that will follow */
451     if (strstr(line, "Xfer Wpt")) {
452       gps_data->progress_type = WPT;
453     }
454     if (strstr(line, "Xfer Trk")) {
455       gps_data->progress_type = TRK;
456     }
457     if (strstr(line, "Xfer Rte")) {
458       gps_data->progress_type = RTE;
459     }
460
461     if (strstr(line, "PRDDAT")) {
462       gchar **tokens = g_strsplit(line, " ", 0);
463       gchar info[128];
464       int ilen = 0;
465       int i;
466       int n_tokens = 0;
467
468       while (tokens[n_tokens])
469         n_tokens++;
470
471       if (n_tokens > 8) {
472         for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
473           guint ch;
474           sscanf(tokens[i], "%x", &ch);
475           info[ilen++] = ch;
476         }
477         info[ilen++] = 0;
478         gps_data->info = g_strdup (info);
479         gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
480       }
481       g_strfreev(tokens);
482     }
483     /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
484     if (strstr(line, "Unit:")) {
485       gchar **tokens = g_strsplit(line, "\t", 0);
486       int n_tokens = 0;
487       while (tokens[n_tokens])
488         n_tokens++;
489
490       if (n_tokens > 1) {
491         gps_data->info = g_strdup (tokens[1]);
492         gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
493       }
494       g_strfreev(tokens);
495     }
496     /* Capture some potential errors */
497     if (strstr(line, "[ERROR] GPS")) {
498       gchar **tokens = g_strsplit(line, "\n", 0);
499       gps_data->info = g_strdup(tokens[0]);
500       gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
501       g_strfreev(tokens);
502     }
503     if (strstr(line, "an't in")) {
504       gchar **tokens = g_strsplit(line, "\n", 0);
505       gps_data->info = g_strdup(tokens[0]);
506       gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
507       g_strfreev(tokens);
508     }
509
510     if (strstr(line, "Can't get waypoint")) {
511       gchar **tokens = g_strsplit(line, "\n", 0);
512       gps_data->info = g_strdup(tokens[0]);
513       gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
514       g_strfreev(tokens);
515     }
516     /* tells us how many items there will be */
517     if (strstr(line, "RECORD")) {
518       int lsb, msb, cnt;
519
520       if (strlen(line) > 20) {
521        sscanf(line+17, "%x", &lsb); 
522        sscanf(line+20, "%x", &msb);
523        cnt = lsb + msb * 256;
524        if ( gps_data->progress_type == RTE ) {
525           // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
526           gint mycnt = (cnt / 2) + 1;
527           gps_data->rte_total_count = mycnt;
528           gps_data->rte_count = 0;
529        }
530        else if ( gps_data->progress_type == TRK ) {
531          gps_data->trk_total_count = cnt;
532          gps_data->trk_count = 0;
533        }
534        else {
535           gps_data->wpt_total_count = cnt;
536           gps_data->wpt_count = 0;
537        }
538
539        gps_data->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, w);
540       }
541     }
542     if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
543       if ( strstr(line, "WPTDAT") )
544         gps_data->wpt_count++;
545       else if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") )
546         gps_data->trk_count++;
547       else
548         // "RTEHDR" || "RTEWPT"
549         gps_data->rte_count++;
550       gps_data->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, w);
551     }
552     break;
553   case BABEL_DONE:
554     break;
555   default:
556     break;
557   }
558 }
559
560 void append_element (gpointer elem, gpointer user_data)
561 {
562   const gchar *text = ((BabelDevice*)elem)->label;
563   vik_combo_box_text_append (GTK_WIDGET(user_data), text);
564 }
565
566 static gint find_entry = -1;
567 static gint wanted_entry = -1;
568
569 static void find_protocol (gpointer elem, gpointer user_data)
570 {
571   const gchar *name = ((BabelDevice*)elem)->name;
572   const gchar *protocol = user_data;
573   find_entry++;
574   if (!strcmp(name, protocol)) {
575     wanted_entry = find_entry;
576   }
577 }
578
579 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
580 {
581   gps_user_data_t *w = (gps_user_data_t *)user_data;
582   GtkTable *box, *data_type_box;
583
584   w->proto_l = gtk_label_new (_("GPS Protocol:"));
585   w->proto_b = vik_combo_box_text_new ();
586   g_list_foreach (a_babel_device_list, append_element, w->proto_b);
587
588   if ( last_active < 0 ) {
589     find_entry = -1;
590     wanted_entry = -1;
591     gchar *protocol = NULL;
592     if ( a_settings_get_string ( VIK_SETTINGS_GPS_PROTOCOL, &protocol ) ) {
593       // Use setting
594       if ( protocol )
595         g_list_foreach (a_babel_device_list, find_protocol, protocol);
596     }
597     else {
598       // Attempt to maintain default to Garmin devices (assumed most popular/numerous device)
599       g_list_foreach (a_babel_device_list, find_protocol, "garmin");
600     }
601     // If not found set it to the first entry, otherwise use the entry
602     last_active = ( wanted_entry < 0 ) ? 0 : wanted_entry;
603   }
604
605   gtk_combo_box_set_active (GTK_COMBO_BOX(w->proto_b), last_active);
606   g_object_ref(w->proto_b);
607
608   w->ser_l = gtk_label_new (_("Serial Port:"));
609 #if GTK_CHECK_VERSION (2, 24, 0)
610   w->ser_b = gtk_combo_box_text_new_with_entry ();
611 #else
612   w->ser_b = gtk_combo_box_entry_new_text ();
613 #endif
614   // Value from the settings is promoted to the top
615   gchar *gps_port = NULL;
616   if ( a_settings_get_string ( VIK_SETTINGS_GPS_PORT, &gps_port ) ) {
617     // Use setting if available
618     if ( gps_port ) {
619 #ifndef WINDOWS
620       if ( !strncmp (gps_port, "/dev/tty", 6) ) {
621         if (g_access (gps_port, R_OK) == 0) {
622           vik_combo_box_text_append (w->ser_b, gps_port);
623         }
624       }
625       else
626 #endif
627         vik_combo_box_text_append (w->ser_b, gps_port);
628     }
629   }
630
631   // Note avoid appending the port selected from the settings
632 #ifdef WINDOWS
633   if ( gps_port && strcmp (gps_port, "com1") )
634     vik_combo_box_text_append (w->ser_b, "com1");
635 #else
636   /* Here just try to see if the device is available which gets passed onto gpsbabel
637      List USB devices first as these will generally only be present if autogenerated by udev or similar
638      User is still able to set their own free text entry */
639   if ( gps_port && strcmp (gps_port, "/dev/ttyUSB0") )
640     if (g_access ("/dev/ttyUSB0", R_OK) == 0)
641       vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB0");
642   if ( gps_port && strcmp (gps_port, "/dev/ttyUSB1") )
643     if (g_access ("/dev/ttyUSB1", R_OK) == 0)
644       vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB1");
645   if ( gps_port && strcmp (gps_port, "/dev/ttyS0") )
646     if (g_access ("/dev/ttyS0", R_OK) == 0)
647       vik_combo_box_text_append (w->ser_b, "/dev/ttyS0");
648   if ( gps_port && strcmp (gps_port, "/dev/ttyS1") )
649     if (g_access ("/dev/ttyS1", R_OK) == 0)
650       vik_combo_box_text_append (w->ser_b, "/dev/ttyS1");
651 #endif
652   if ( gps_port && strcmp (gps_port, "usb:") )
653     vik_combo_box_text_append (w->ser_b, "usb:");
654
655   gtk_combo_box_set_active (GTK_COMBO_BOX(w->ser_b), 0);
656   g_object_ref(w->ser_b);
657
658   w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
659   w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
660   gboolean power_off;
661   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_POWER_OFF, &power_off ) )
662     power_off = FALSE;
663   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->off_request_b), power_off);
664
665   w->get_tracks_l = gtk_label_new (_("Tracks:"));
666   w->get_tracks_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
667   gboolean get_tracks;
668   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, &get_tracks ) )
669     get_tracks = TRUE;
670   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), get_tracks);
671
672   w->get_routes_l = gtk_label_new (_("Routes:"));
673   w->get_routes_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
674   gboolean get_routes;
675   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, &get_routes ) )
676     get_routes = FALSE;
677   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_routes_b), get_routes);
678
679   w->get_waypoints_l = gtk_label_new (_("Waypoints:"));
680   w->get_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
681   gboolean get_waypoints;
682   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, &get_waypoints ) )
683     get_waypoints = TRUE;
684   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), get_waypoints);
685
686   box = GTK_TABLE(gtk_table_new(2, 4, FALSE));
687   data_type_box = GTK_TABLE(gtk_table_new(4, 1, FALSE));
688
689   gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_l), 0, 1, 0, 1);
690   gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_b), 1, 2, 0, 1);
691   gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_l), 0, 1, 1, 2);
692   gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_b), 1, 2, 1, 2);
693   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_l), 0, 1, 0, 1);
694   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_b), 1, 2, 0, 1);
695   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_routes_l), 2, 3, 0, 1);
696   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_routes_b), 3, 4, 0, 1);
697   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_l), 4, 5, 0, 1);
698   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_b), 5, 6, 0, 1);
699   gtk_table_attach_defaults(box, GTK_WIDGET(data_type_box), 0, 2, 2, 3);
700   gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_l), 0, 1, 3, 4);
701   gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_b), 1, 3, 3, 4);
702   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
703
704   gtk_widget_show_all ( dialog );
705 }
706
707 /**
708  * datasource_gps_setup:
709  * @dialog: The GTK dialog. The caller is responsible for managing the dialog creation/deletion
710  * @xfer: The default type of items enabled for transfer, others disabled.
711  * @xfer_all: When specified all items are enabled for transfer.
712  *
713  * Returns: A gpointer to the private structure for GPS progress/information widgets
714  *          Pass this pointer back into the other exposed datasource_gps_X functions
715  */
716 gpointer datasource_gps_setup ( GtkWidget *dialog, vik_gps_xfer_type xfer, gboolean xfer_all )
717 {
718   gps_user_data_t *w_gps = (gps_user_data_t *)datasource_gps_init_func ( NULL );
719   w_gps->direction = GPS_UP;
720   datasource_gps_add_setup_widgets ( dialog, NULL, w_gps );
721
722   gboolean way = xfer_all;
723   gboolean trk = xfer_all;
724   gboolean rte = xfer_all;
725
726   // Selectively turn bits on
727   if ( !xfer_all ) {
728     switch (xfer) {
729     case WPT: way = TRUE; break;
730     case RTE: rte = TRUE; break;
731     default: trk = TRUE; break;
732     }
733   }
734
735   // Apply
736   gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_tracks_b), trk );
737   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_tracks_l), trk );
738   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_tracks_b), trk );
739
740   gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_routes_b), rte );
741   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_routes_l), rte );
742   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_routes_b), rte );
743
744   gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_waypoints_b), way );
745   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_waypoints_l), way );
746   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_waypoints_b), way );
747
748   return (gpointer)w_gps;
749 }
750
751 void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
752 {
753   gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
754
755   w_gps->gps_label = gtk_label_new (_("GPS device: N/A"));
756   w_gps->wpt_label = gtk_label_new ("");
757   w_gps->trk_label = gtk_label_new ("");
758   w_gps->rte_label = gtk_label_new ("");
759
760   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->gps_label, FALSE, FALSE, 5 );
761   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->wpt_label, FALSE, FALSE, 5 );
762   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->trk_label, FALSE, FALSE, 5 );
763   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->rte_label, FALSE, FALSE, 5 );
764
765   gtk_widget_show_all ( dialog );
766 }