]> git.street.me.uk Git - andy/viking.git/blobdiff - src/datasource_gps.c
Fix spelling in gpsd retry warning print out
[andy/viking.git] / src / datasource_gps.c
index 962efc46c84eb41ef4d006c952f595ba21536e77..7fd7ff90ab1a63d7fae90c9edd8b2b0d9d27a44a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
  * Copyright (C) 2006, Alex Foobarian <foobarian@gmail.com>
- * Copyright (C) 2012, Rob Norris <rw_norris@hotmail.com>
+ * Copyright (C) 2012-2015, Rob Norris <rw_norris@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 static gboolean gps_acquire_in_progress = FALSE;
 
 static gint last_active = -1;
-static gboolean last_get_tracks = TRUE;
-static gboolean last_get_routes = TRUE;
-static gboolean last_get_waypoints = TRUE;
 
-static gpointer datasource_gps_init_func ( );
-static void datasource_gps_get_cmd_string ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file, gpointer not_used );
+static gpointer datasource_gps_init_func ( acq_vik_t *avt );
+static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 );
 static void datasource_gps_cleanup ( gpointer user_data );
 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
@@ -56,7 +53,7 @@ static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **bab
 VikDataSourceInterface vik_datasource_gps_interface = {
   N_("Acquire from GPS"),
   N_("Acquired from GPS"),
-  VIK_DATASOURCE_CREATENEWLAYER,
+  VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT,
   VIK_DATASOURCE_INPUTTYPE_NONE,
   TRUE,
   TRUE,
@@ -64,12 +61,18 @@ VikDataSourceInterface vik_datasource_gps_interface = {
   (VikDataSourceInitFunc)              datasource_gps_init_func,
   (VikDataSourceCheckExistenceFunc)    NULL,
   (VikDataSourceAddSetupWidgetsFunc)   datasource_gps_add_setup_widgets,
-  (VikDataSourceGetCmdStringFunc)      datasource_gps_get_cmd_string,
-  (VikDataSourceProcessFunc)        a_babel_convert_from,
+  (VikDataSourceGetProcessOptionsFunc)  datasource_gps_get_process_options,
+  (VikDataSourceProcessFunc)            a_babel_convert_from,
   (VikDataSourceProgressFunc)          datasource_gps_progress,
   (VikDataSourceAddProgressWidgetsFunc)        datasource_gps_add_progress_widgets,
   (VikDataSourceCleanupFunc)           datasource_gps_cleanup,
-  (VikDataSourceOffFunc)                datasource_gps_off
+  (VikDataSourceOffFunc)                datasource_gps_off,
+
+  NULL,
+  0,
+  NULL,
+  NULL,
+  0
 };
 
 /*********************************************************
@@ -96,22 +99,40 @@ typedef struct {
 
   /* progress dialog */
   GtkWidget *gps_label;
-  GtkWidget *ver_label;
-  GtkWidget *id_label;
-  GtkWidget *wp_label;
+  GtkWidget *wpt_label;
   GtkWidget *trk_label;
   GtkWidget *rte_label;
-  GtkWidget *progress_label;
   vik_gps_xfer_type progress_type;
 
-  /* state */
-  int total_count;
-  int count;
+  // Maintain separate counts for each type
+  int wpt_total_count;
+  int wpt_count;
+  int trk_total_count;
+  int trk_count;
+  int rte_total_count;
+  int rte_count;
+  gchar *info;
+  // Know which way xfer is so xfer setting types are only stored for download
+  vik_gps_dir direction;
+  // GUI Updates
+  gint id_status;
+  gint id_info;
+  gint id_total_count;
+  gint id_count;
 } gps_user_data_t;
 
-static gpointer datasource_gps_init_func ()
+#define VIK_SETTINGS_GPS_GET_TRACKS "gps_download_tracks"
+#define VIK_SETTINGS_GPS_GET_ROUTES "gps_download_routes"
+#define VIK_SETTINGS_GPS_GET_WAYPOINTS "gps_download_waypoints"
+#define VIK_SETTINGS_GPS_PROTOCOL "gps_protocol"
+#define VIK_SETTINGS_GPS_PORT "gps_port"
+#define VIK_SETTINGS_GPS_POWER_OFF "gps_power_off"
+
+static gpointer datasource_gps_init_func ( acq_vik_t *avt )
 {
-  return g_malloc (sizeof(gps_user_data_t));
+  gps_user_data_t *gps_ud = g_malloc0 (sizeof(gps_user_data_t));
+  gps_ud->direction = GPS_DOWN;
+  return gps_ud;
 }
 
 /**
@@ -124,8 +145,11 @@ gchar* datasource_gps_get_protocol ( gpointer user_data )
   // Uses the list of supported devices
   gps_user_data_t *w = (gps_user_data_t *)user_data;
   last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
-  if (a_babel_device_list)
-    return ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
+  if (a_babel_device_list) {
+    gchar *protocol = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
+    a_settings_set_string ( VIK_SETTINGS_GPS_PROTOCOL, protocol );
+    return protocol;
+  }
 
   return NULL;
 }
@@ -142,10 +166,12 @@ gchar* datasource_gps_get_descriptor ( gpointer user_data )
   gps_user_data_t *w = (gps_user_data_t *)user_data;
 
 #if GTK_CHECK_VERSION (2, 24, 0)
-  return gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
+  gchar *descriptor = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
 #else
-  return gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
+  gchar *descriptor = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
 #endif
+  a_settings_set_string ( VIK_SETTINGS_GPS_PORT, descriptor );
+  return descriptor;
 }
 
 /**
@@ -156,8 +182,10 @@ gchar* datasource_gps_get_descriptor ( gpointer user_data )
 gboolean datasource_gps_get_do_tracks ( gpointer user_data )
 {
   gps_user_data_t *w = (gps_user_data_t *)user_data;
-  last_get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
-  return last_get_tracks;
+  gboolean get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
+  if ( w->direction == GPS_DOWN )
+    a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, get_tracks );
+  return get_tracks;
 }
 
 /**
@@ -168,8 +196,10 @@ gboolean datasource_gps_get_do_tracks ( gpointer user_data )
 gboolean datasource_gps_get_do_routes ( gpointer user_data )
 {
   gps_user_data_t *w = (gps_user_data_t *)user_data;
-  last_get_routes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_routes_b));
-  return last_get_routes;
+  gboolean get_routes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_routes_b));
+  if ( w->direction == GPS_DOWN )
+    a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, get_routes );
+  return get_routes;
 }
 
 /**
@@ -180,11 +210,13 @@ gboolean datasource_gps_get_do_routes ( gpointer user_data )
 gboolean datasource_gps_get_do_waypoints ( gpointer user_data )
 {
   gps_user_data_t *w = (gps_user_data_t *)user_data;
-  last_get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
-  return last_get_waypoints;
+  gboolean get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
+  if ( w->direction == GPS_DOWN )
+    a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, get_waypoints );
+  return get_waypoints;
 }
 
-static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelargs, gchar **input_file, gpointer not_used )
+static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 )
 {
   char *device = NULL;
   char *tracks = NULL;
@@ -192,7 +224,7 @@ static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelarg
   char *waypoints = NULL;
 
   if (gps_acquire_in_progress) {
-    *babelargs = *input_file = NULL;
+    po->babelargs = po->filename = NULL;
   }
   
   gps_acquire_in_progress = TRUE;
@@ -214,16 +246,16 @@ static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelarg
   else
     waypoints = "";
 
-  *babelargs = g_strdup_printf("-D 9 %s %s %s -i %s", tracks, routes, waypoints, device);
+  po->babelargs = g_strdup_printf("-D 9 %s %s %s -i %s", tracks, routes, waypoints, device);
   /* device points to static content => no free */
   device = NULL;
   tracks = NULL;
   routes = NULL;
   waypoints = NULL;
 
-  *input_file = g_strdup(datasource_gps_get_descriptor(user_data));
+  po->filename = g_strdup(datasource_gps_get_descriptor(user_data));
 
-  g_debug(_("using cmdline '%s' and file '%s'\n"), *babelargs, *input_file);
+  g_debug(_("using cmd '%s' and file '%s'\n"), po->babelargs, po->filename);
 }
 
 /**
@@ -234,17 +266,19 @@ static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelarg
 gboolean datasource_gps_get_off ( gpointer user_data )
 {
   gps_user_data_t *w = (gps_user_data_t *)user_data;
-  return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b));
+  gboolean power_off = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b));
+  a_settings_set_boolean ( VIK_SETTINGS_GPS_POWER_OFF, power_off );
+  return power_off;
 }
 
-static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **input_file )
+static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **file_descriptor )
 {
   char *ser = NULL;
   char *device = NULL;
   gps_user_data_t *w = (gps_user_data_t *)user_data;
 
   if (gps_acquire_in_progress) {
-    *babelargs = *input_file = NULL;
+    *babelargs = *file_descriptor = NULL;
   }
 
   /* See if we should turn off the device */
@@ -275,13 +309,24 @@ static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **
 #else
   ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
 #endif
-  *input_file = g_strdup(ser);
+  *file_descriptor = g_strdup(ser);
 }
 
 
 static void datasource_gps_cleanup ( gpointer user_data )
 {
-  g_free ( user_data );
+  gps_user_data_t *gud = (gps_user_data_t *)user_data;
+  // Remove any outstanding GUI update requests
+  if ( gud->id_status )
+    g_source_remove ( gud->id_status );
+  if ( gud->id_info )
+    g_source_remove ( gud->id_info );
+  if ( gud->id_total_count )
+    g_source_remove ( gud->id_total_count );
+  if ( gud->id_count )
+    g_source_remove ( gud->id_count );
+  g_free ( gud->info );
+  g_free ( gud );
   gps_acquire_in_progress = FALSE;
 }
 
@@ -295,69 +340,95 @@ void datasource_gps_clean_up ( gpointer user_data )
   datasource_gps_cleanup ( user_data );
 }
 
-static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
+static gboolean show_total_count(acq_dialog_widgets_t *w)
 {
-  gchar *s = NULL;
-  gdk_threads_enter();
+  gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
   if (w->running) {
-    gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
+    gint tmp_count;
+    GtkWidget *progress_label;
     const gchar *tmp_str;
     switch (gps_data->progress_type) {
-    case WPT: tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt); gps_data->total_count = cnt; break;
-    case TRK: tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt); gps_data->total_count = cnt; break;
+    case WPT:
+      progress_label = gps_data->wpt_label;
+      tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", gps_data->wpt_total_count);
+      tmp_count = gps_data->wpt_total_count;
+      break;
+    case TRK:
+      progress_label = gps_data->trk_label;
+      tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", gps_data->trk_total_count);
+      tmp_count = gps_data->trk_total_count;
+      break;
     default:
-      {
-        // 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
-        gint mycnt = (cnt / 2) + 1;
-        tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", mycnt);
-        gps_data->total_count = mycnt;
-        break;
-      }
+      progress_label = gps_data->rte_label;
+      tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", gps_data->rte_total_count);
+      tmp_count = gps_data->rte_total_count;
+      break;
     }
-    s = g_strdup_printf(tmp_str, cnt);
-    gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
-    gtk_widget_show ( gps_data->progress_label );
+    gchar *s = g_strdup_printf(tmp_str, tmp_count);
+    gtk_label_set_text ( GTK_LABEL(progress_label), s );
+    gtk_widget_show ( progress_label );
+    g_free(s);
   }
-  g_free(s); s = NULL;
-  gdk_threads_leave();
+  gps_data->id_total_count = 0;
+  return FALSE;
 }
 
-static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
+static gboolean show_current_count(acq_dialog_widgets_t *w)
 {
-  gchar *s = NULL;
-  gdk_threads_enter();
+  gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
   if (w->running) {
-    gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
-
-    if (cnt < gps_data->total_count) {
-      switch (gps_data->progress_type) {
-      case WPT: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "waypoints"); break;
-      case TRK: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "trackpoints"); break;
-      default: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "routepoints"); break;
-      }
-    } else {
-      switch (gps_data->progress_type) {
-      case WPT: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "waypoints"); break;
-      case TRK: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "trackpoints"); break;
-      default: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "routepoints"); break;
-      }
+    GtkWidget *progress_label;
+    gchar *s = NULL;
+    switch (gps_data->progress_type) {
+      case WPT:
+        progress_label = gps_data->wpt_label;
+        if ( gps_data->wpt_count < gps_data->wpt_total_count )
+          s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->wpt_count, gps_data->wpt_total_count, "waypoints");
+        else
+          s = g_strdup_printf(_("Downloaded %d %s."), gps_data->wpt_count, "waypoints");
+        break;
+      case TRK:
+        progress_label = gps_data->trk_label;
+        if ( gps_data->trk_count < gps_data->trk_total_count )
+          s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->trk_count, gps_data->trk_total_count, "trackpoints");
+        else
+          s = g_strdup_printf(_("Downloaded %d %s."), gps_data->trk_count, "trackpoints");
+        break;
+      default:
+        progress_label = gps_data->rte_label;
+        if ( gps_data->rte_count < gps_data->rte_total_count )
+          s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->rte_count, gps_data->rte_total_count, "routepoints");
+        else
+          s = g_strdup_printf(_("Downloaded %d %s."), gps_data->rte_count, "routepoints");
+        break;
     }
-    gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
+    gtk_label_set_text ( GTK_LABEL(progress_label), s );
+    g_free(s);
+  }
+  gps_data->id_count = 0;
+  return FALSE;
+}
+
+static gboolean show_gps_info(acq_dialog_widgets_t *w)
+{
+  gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
+  if (w->running) {
+    gchar *s = g_strdup_printf ( _("GPS Device: %s"), gps_data->info );
+    gtk_label_set_text ( GTK_LABEL(gps_data->gps_label), s );
+    g_free(s);
   }
-  g_free(s); s = NULL;
-  gdk_threads_leave();
+  gps_data->id_info = 0;
+  return FALSE;
 }
 
-static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
+static gboolean show_gps_status(acq_dialog_widgets_t *w)
 {
-  gchar *s = NULL;
-  gdk_threads_enter();
+  gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
   if (w->running) {
-    s = g_strdup_printf(_("GPS Device: %s"), info);
-    gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
+    gtk_label_set_text ( GTK_LABEL(w->status), _("Status: Working...") );
   }
-  g_free(s); s = NULL;
-  gdk_threads_leave();
+  gps_data->id_status = 0;
+  return FALSE;
 }
 
 /* 
@@ -374,23 +445,16 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
   case BABEL_DIAG_OUTPUT:
     line = (gchar *)data;
 
-    gdk_threads_enter();
-    if (w->running) {
-      gtk_label_set_text ( GTK_LABEL(w->status), _("Status: Working...") );
-    }
-    gdk_threads_leave();
+    gps_data->id_status = gdk_threads_add_idle ( (GSourceFunc)show_gps_status, w );
 
     /* tells us the type of items that will follow */
     if (strstr(line, "Xfer Wpt")) {
-      gps_data->progress_label = gps_data->wp_label;
       gps_data->progress_type = WPT;
     }
     if (strstr(line, "Xfer Trk")) {
-      gps_data->progress_label = gps_data->trk_label;
       gps_data->progress_type = TRK;
     }
     if (strstr(line, "Xfer Rte")) {
-      gps_data->progress_label = gps_data->rte_label;
       gps_data->progress_type = RTE;
     }
 
@@ -411,7 +475,8 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
          info[ilen++] = ch;
         }
         info[ilen++] = 0;
-        set_gps_info(info, w);
+        gps_data->info = g_strdup (info);
+        gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
       }
       g_strfreev(tokens);
     }
@@ -423,10 +488,31 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
         n_tokens++;
 
       if (n_tokens > 1) {
-        set_gps_info(tokens[1], w);
+        gps_data->info = g_strdup (tokens[1]);
+        gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
       }
       g_strfreev(tokens);
     }
+    /* Capture some potential errors */
+    if (strstr(line, "[ERROR] GPS")) {
+      gchar **tokens = g_strsplit(line, "\n", 0);
+      gps_data->info = g_strdup(tokens[0]);
+      gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
+      g_strfreev(tokens);
+    }
+    if (strstr(line, "an't in")) {
+      gchar **tokens = g_strsplit(line, "\n", 0);
+      gps_data->info = g_strdup(tokens[0]);
+      gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
+      g_strfreev(tokens);
+    }
+
+    if (strstr(line, "Can't get waypoint")) {
+      gchar **tokens = g_strsplit(line, "\n", 0);
+      gps_data->info = g_strdup(tokens[0]);
+      gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
+      g_strfreev(tokens);
+    }
     /* tells us how many items there will be */
     if (strstr(line, "RECORD")) {
       int lsb, msb, cnt;
@@ -435,13 +521,33 @@ static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_di
        sscanf(line+17, "%x", &lsb); 
        sscanf(line+20, "%x", &msb);
        cnt = lsb + msb * 256;
-       set_total_count(cnt, w);
-       gps_data->count = 0;
+       if ( gps_data->progress_type == RTE ) {
+          // 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
+          gint mycnt = (cnt / 2) + 1;
+          gps_data->rte_total_count = mycnt;
+          gps_data->rte_count = 0;
+       }
+       else if ( gps_data->progress_type == TRK ) {
+         gps_data->trk_total_count = cnt;
+         gps_data->trk_count = 0;
+       }
+       else {
+          gps_data->wpt_total_count = cnt;
+          gps_data->wpt_count = 0;
+       }
+
+       gps_data->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, w);
       }
     }
     if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
-      gps_data->count++;
-      set_current_count(gps_data->count, w);
+      if ( strstr(line, "WPTDAT") )
+        gps_data->wpt_count++;
+      else if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") )
+        gps_data->trk_count++;
+      else
+        // "RTEHDR" || "RTEWPT"
+        gps_data->rte_count++;
+      gps_data->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, w);
     }
     break;
   case BABEL_DONE:
@@ -458,14 +564,15 @@ void append_element (gpointer elem, gpointer user_data)
 }
 
 static gint find_entry = -1;
-static gint garmin_entry = -1;
+static gint wanted_entry = -1;
 
-static void find_garmin (gpointer elem, gpointer user_data)
+static void find_protocol (gpointer elem, gpointer user_data)
 {
   const gchar *name = ((BabelDevice*)elem)->name;
+  const gchar *protocol = user_data;
   find_entry++;
-  if (!strcmp(name, "garmin")) {
-    garmin_entry = find_entry;
+  if (!strcmp(name, protocol)) {
+    wanted_entry = find_entry;
   }
 }
 
@@ -478,16 +585,21 @@ static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *v
   w->proto_b = vik_combo_box_text_new ();
   g_list_foreach (a_babel_device_list, append_element, w->proto_b);
 
-  // Maintain default to Garmin devices (assumed most popular/numerous device)
   if ( last_active < 0 ) {
     find_entry = -1;
-    g_list_foreach (a_babel_device_list, find_garmin, NULL);
-    if ( garmin_entry < 0 )
-      // Not found - so set it to the first entry
-      last_active = 0;
-    else
-      // Found
-      last_active = garmin_entry;
+    wanted_entry = -1;
+    gchar *protocol = NULL;
+    if ( a_settings_get_string ( VIK_SETTINGS_GPS_PROTOCOL, &protocol ) ) {
+      // Use setting
+      if ( protocol )
+        g_list_foreach (a_babel_device_list, find_protocol, protocol);
+    }
+    else {
+      // Attempt to maintain default to Garmin devices (assumed most popular/numerous device)
+      g_list_foreach (a_babel_device_list, find_protocol, "garmin");
+    }
+    // If not found set it to the first entry, otherwise use the entry
+    last_active = ( wanted_entry < 0 ) ? 0 : wanted_entry;
   }
 
   gtk_combo_box_set_active (GTK_COMBO_BOX(w->proto_b), last_active);
@@ -499,39 +611,77 @@ static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *v
 #else
   w->ser_b = gtk_combo_box_entry_new_text ();
 #endif
+  // Value from the settings is promoted to the top
+  gchar *gps_port = NULL;
+  if ( a_settings_get_string ( VIK_SETTINGS_GPS_PORT, &gps_port ) ) {
+    // Use setting if available
+    if ( gps_port ) {
+#ifndef WINDOWS
+      if ( !strncmp (gps_port, "/dev/tty", 6) ) {
+        if (g_access (gps_port, R_OK) == 0) {
+          vik_combo_box_text_append (w->ser_b, gps_port);
+       }
+      }
+      else
+#endif
+        vik_combo_box_text_append (w->ser_b, gps_port);
+    }
+  }
+
+  // Note avoid appending the port selected from the settings
 #ifdef WINDOWS
-  vik_combo_box_text_append (w->ser_b, "com1");
+  if ( gps_port && strcmp (gps_port, "com1") )
+    vik_combo_box_text_append (w->ser_b, "com1");
 #else
   /* Here just try to see if the device is available which gets passed onto gpsbabel
      List USB devices first as these will generally only be present if autogenerated by udev or similar
      User is still able to set their own free text entry */
-  if (g_access ("/dev/ttyUSB0", R_OK) == 0)
-    vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB0");
-  if (g_access ("/dev/ttyUSB1", R_OK) == 0)
-    vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB1");
-  if (g_access ("/dev/ttyS0", R_OK) == 0)
-    vik_combo_box_text_append (w->ser_b, "/dev/ttyS0");
-  if (g_access ("/dev/ttyS1", R_OK) == 0)
-    vik_combo_box_text_append (w->ser_b, "/dev/ttyS1");
+  if ( gps_port && strcmp (gps_port, "/dev/ttyUSB0") )
+    if (g_access ("/dev/ttyUSB0", R_OK) == 0)
+      vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB0");
+  if ( gps_port && strcmp (gps_port, "/dev/ttyUSB1") )
+    if (g_access ("/dev/ttyUSB1", R_OK) == 0)
+      vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB1");
+  if ( gps_port && strcmp (gps_port, "/dev/ttyS0") )
+    if (g_access ("/dev/ttyS0", R_OK) == 0)
+      vik_combo_box_text_append (w->ser_b, "/dev/ttyS0");
+  if ( gps_port && strcmp (gps_port, "/dev/ttyS1") )
+    if (g_access ("/dev/ttyS1", R_OK) == 0)
+      vik_combo_box_text_append (w->ser_b, "/dev/ttyS1");
 #endif
-  vik_combo_box_text_append (w->ser_b, "usb:");
+  if ( gps_port && strcmp (gps_port, "usb:") )
+    vik_combo_box_text_append (w->ser_b, "usb:");
+
   gtk_combo_box_set_active (GTK_COMBO_BOX(w->ser_b), 0);
   g_object_ref(w->ser_b);
 
   w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
   w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
+  gboolean power_off;
+  if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_POWER_OFF, &power_off ) )
+    power_off = FALSE;
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->off_request_b), power_off);
 
   w->get_tracks_l = gtk_label_new (_("Tracks:"));
   w->get_tracks_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
-  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), last_get_tracks);
+  gboolean get_tracks;
+  if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, &get_tracks ) )
+    get_tracks = TRUE;
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), get_tracks);
 
   w->get_routes_l = gtk_label_new (_("Routes:"));
   w->get_routes_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
-  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_routes_b), last_get_routes);
+  gboolean get_routes;
+  if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, &get_routes ) )
+    get_routes = FALSE;
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_routes_b), get_routes);
 
   w->get_waypoints_l = gtk_label_new (_("Waypoints:"));
   w->get_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
-  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), last_get_waypoints);
+  gboolean get_waypoints;
+  if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, &get_waypoints ) )
+    get_waypoints = TRUE;
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), get_waypoints);
 
   box = GTK_TABLE(gtk_table_new(2, 4, FALSE));
   data_type_box = GTK_TABLE(gtk_table_new(4, 1, FALSE));
@@ -565,7 +715,8 @@ static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *v
  */
 gpointer datasource_gps_setup ( GtkWidget *dialog, vik_gps_xfer_type xfer, gboolean xfer_all )
 {
-  gps_user_data_t *w_gps = (gps_user_data_t *)datasource_gps_init_func();
+  gps_user_data_t *w_gps = (gps_user_data_t *)datasource_gps_init_func ( NULL );
+  w_gps->direction = GPS_UP;
   datasource_gps_add_setup_widgets ( dialog, NULL, w_gps );
 
   gboolean way = xfer_all;
@@ -599,29 +750,17 @@ gpointer datasource_gps_setup ( GtkWidget *dialog, vik_gps_xfer_type xfer, gbool
 
 void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
 {
-  GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel, *rtelabel;
-
   gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
 
-  gpslabel = gtk_label_new (_("GPS device: N/A"));
-  verlabel = gtk_label_new ("");
-  idlabel = gtk_label_new ("");
-  wplabel = gtk_label_new ("");
-  trklabel = gtk_label_new ("");
-  rtelabel = gtk_label_new ("");
+  w_gps->gps_label = gtk_label_new (_("GPS device: N/A"));
+  w_gps->wpt_label = gtk_label_new ("");
+  w_gps->trk_label = gtk_label_new ("");
+  w_gps->rte_label = gtk_label_new ("");
 
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), gpslabel, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), wplabel, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), trklabel, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), rtelabel, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->gps_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->wpt_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->trk_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->rte_label, FALSE, FALSE, 5 );
 
   gtk_widget_show_all ( dialog );
-
-  w_gps->gps_label = gpslabel;
-  w_gps->id_label = idlabel;
-  w_gps->ver_label = verlabel;
-  w_gps->progress_label = w_gps->wp_label = wplabel;
-  w_gps->trk_label = trklabel;
-  w_gps->rte_label = rtelabel;
-  w_gps->total_count = -1;
 }