]> git.street.me.uk Git - andy/viking.git/blob - src/datasource_gps.c
When getting data via the GPS layer automatically set the view to see it, unless...
[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) 2010, 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 "viking.h"
36 #include "babel.h"
37 #include "gpx.h"
38 #include "acquire.h"
39
40 #if GTK_CHECK_VERSION(2,6,0)
41 #define USE_NEW_COMBO_BOX
42 #endif
43
44 static gboolean gps_acquire_in_progress = FALSE;
45
46 static gpointer datasource_gps_init_func ( );
47 static void datasource_gps_get_cmd_string ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
48 static void datasource_gps_cleanup ( gpointer user_data );
49 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
50 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
51 static void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data );
52 static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
53
54 VikDataSourceInterface vik_datasource_gps_interface = {
55   N_("Acquire from GPS"),
56   N_("Acquired from GPS"),
57   VIK_DATASOURCE_GPSBABEL_DIRECT,
58   VIK_DATASOURCE_CREATENEWLAYER,
59   VIK_DATASOURCE_INPUTTYPE_NONE,
60   TRUE,
61   TRUE,
62   (VikDataSourceInitFunc)               datasource_gps_init_func,
63   (VikDataSourceCheckExistenceFunc)     NULL,
64   (VikDataSourceAddSetupWidgetsFunc)    datasource_gps_add_setup_widgets,
65   (VikDataSourceGetCmdStringFunc)       datasource_gps_get_cmd_string,
66   (VikDataSourceProgressFunc)           datasource_gps_progress,
67   (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
68   (VikDataSourceCleanupFunc)            datasource_gps_cleanup,
69   (VikDataSourceOffFunc)                datasource_gps_off
70 };
71
72 /*********************************************************
73  * Definitions and routines for acquiring data from GPS
74  *********************************************************/
75
76 /* widgets in setup dialog specific to GPS */
77 /* widgets in progress dialog specific to GPS */
78 /* also counts needed for progress */
79 typedef struct {
80   /* setup dialog */
81   GtkWidget *proto_l;
82   GtkComboBox *proto_b;
83   GtkWidget *ser_l;
84   GtkComboBox *ser_b;
85   GtkWidget *off_request_l;
86   GtkCheckButton *off_request_b;
87
88   /* progress dialog */
89   GtkWidget *gps_label;
90   GtkWidget *ver_label;
91   GtkWidget *id_label;
92   GtkWidget *wp_label;
93   GtkWidget *trk_label;
94   GtkWidget *progress_label;
95
96   /* state */
97   int total_count;
98   int count;
99 } gps_user_data_t;
100
101 static gpointer datasource_gps_init_func ()
102 {
103   return g_malloc (sizeof(gps_user_data_t));
104 }
105
106 static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelargs, gchar **input_file )
107 {
108   char *proto = NULL;
109   char *ser = NULL;
110   char *device = NULL;
111 #ifndef USE_NEW_COMBO_BOX
112   GtkTreeIter iter;
113 #endif
114   gps_user_data_t *w = (gps_user_data_t *)user_data;
115
116   if (gps_acquire_in_progress) {
117     *babelargs = *input_file = NULL;
118   }
119   
120   gps_acquire_in_progress = TRUE;
121
122 #ifdef USE_NEW_COMBO_BOX
123   proto = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->proto_b));
124 #else
125   proto = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->proto_b),&iter);
126 #endif
127   if (!strcmp(proto, "Garmin")) {
128     device = "garmin";
129   } else if (!strcmp(proto, "Magellan")) {
130     device = "magellan";
131   }
132   else if (!strcmp(proto, "DeLorme")) {
133     device = "delbin";
134   }
135   else {
136     device = "navilink";
137   }
138
139   *babelargs = g_strdup_printf("-D 9 -t -w -i %s", device);
140   /* device points to static content => no free */
141   device = NULL;
142   
143   /* Old stuff */
144 #ifdef USE_NEW_COMBO_BOX
145   ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
146 #else
147   ser = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->ser_b),&iter);
148 #endif
149   *input_file = g_strdup(ser);
150
151   g_debug(_("using cmdline '%s' and file '%s'\n"), *babelargs, *input_file);
152 }
153
154
155 static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **input_file )
156 {
157   char *proto = NULL;
158   char *ser = NULL;
159   char *device = NULL;
160 #ifndef USE_NEW_COMBO_BOX
161   GtkTreeIter iter;
162 #endif
163   gps_user_data_t *w = (gps_user_data_t *)user_data;
164
165   if (gps_acquire_in_progress) {
166     *babelargs = *input_file = NULL;
167   }
168
169   /* See if we should turn off the device */
170   if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b))) {
171     return;
172   }
173   
174 #ifdef USE_NEW_COMBO_BOX
175   proto = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->proto_b));
176 #else
177   proto = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->proto_b),&iter);
178 #endif
179   if (!strcmp(proto, "Garmin")) {
180     device = "garmin,power_off";
181   }
182   else if (!strcmp(proto, "NAViLink")) {
183     device = "navilink,power_off";
184   }
185   else {
186     return;
187   }
188
189   *babelargs = g_strdup_printf("-i %s", device);
190   /* device points to static content => no free */
191   device = NULL;
192   
193   /* Old stuff */
194 #ifdef USE_NEW_COMBO_BOX
195   ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
196 #else
197   ser = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->ser_b),&iter);
198 #endif
199   *input_file = g_strdup(ser);
200 }
201
202
203 static void datasource_gps_cleanup ( gpointer user_data )
204 {
205   g_free ( user_data );
206   gps_acquire_in_progress = FALSE;
207 }
208
209 static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
210 {
211   gchar *s = NULL;
212   gdk_threads_enter();
213   if (w->ok) {
214     gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
215     const gchar *tmp_str;
216     if (gps_data->progress_label == gps_data->wp_label)
217       tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt);
218     else
219       tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt);
220     s = g_strdup_printf(tmp_str, cnt);
221     gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
222     gtk_widget_show ( gps_data->progress_label );
223     gps_data->total_count = cnt;
224   }
225   g_free(s); s = NULL;
226   gdk_threads_leave();
227 }
228
229 static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
230 {
231   gchar *s = NULL;
232   gdk_threads_enter();
233   if (w->ok) {
234     gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
235
236     if (cnt < gps_data->total_count) {
237       s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
238     } else {
239       s = g_strdup_printf(_("Downloaded %d %s."), cnt, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
240     }     
241     gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
242   }
243   g_free(s); s = NULL;
244   gdk_threads_leave();
245 }
246
247 static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
248 {
249   gchar *s = NULL;
250   gdk_threads_enter();
251   if (w->ok) {
252     s = g_strdup_printf(_("GPS Device: %s"), info);
253     gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
254   }
255   g_free(s); s = NULL;
256   gdk_threads_leave();
257 }
258
259 /* 
260  * This routine relies on gpsbabel's diagnostic output to display the progress information. 
261  * These outputs differ when different GPS devices are used, so we will need to test
262  * them on several and add the corresponding support.
263  */
264 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
265 {
266   gchar *line;
267   gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
268
269   switch(c) {
270   case BABEL_DIAG_OUTPUT:
271     line = (gchar *)data;
272
273     /* tells us how many items there will be */
274     if (strstr(line, "Xfer Wpt")) { 
275       gps_data->progress_label = gps_data->wp_label;
276     }
277     if (strstr(line, "Xfer Trk")) { 
278       gps_data->progress_label = gps_data->trk_label;
279     }
280     if (strstr(line, "PRDDAT")) {
281       gchar **tokens = g_strsplit(line, " ", 0);
282       gchar info[128];
283       int ilen = 0;
284       int i;
285       int n_tokens = 0;
286
287       while (tokens[n_tokens])
288         n_tokens++;
289
290       if (n_tokens > 8) {
291         for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
292           guint ch;
293           sscanf(tokens[i], "%x", &ch);
294           info[ilen++] = ch;
295         }
296         info[ilen++] = 0;
297         set_gps_info(info, w);
298       }
299       g_strfreev(tokens);
300     }
301     /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
302     if (strstr(line, "Unit:")) {
303       gchar **tokens = g_strsplit(line, "\t", 0);
304       int n_tokens = 0;
305       while (tokens[n_tokens])
306         n_tokens++;
307
308       if (n_tokens > 1) {
309         set_gps_info(tokens[1], w);
310       }
311       g_strfreev(tokens);
312     }
313     if (strstr(line, "RECORD")) { 
314       int lsb, msb, cnt;
315
316       if (strlen(line) > 20) {
317        sscanf(line+17, "%x", &lsb); 
318        sscanf(line+20, "%x", &msb);
319        cnt = lsb + msb * 256;
320        set_total_count(cnt, w);
321        gps_data->count = 0;
322       }
323     }
324     if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
325       gps_data->count++;
326       set_current_count(gps_data->count, w);
327     }
328     break;
329   case BABEL_DONE:
330     break;
331   default:
332     break;
333   }
334 }
335
336 void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
337 {
338   gps_user_data_t *w = (gps_user_data_t *)user_data;
339   GtkTable*  box;
340
341   w->proto_l = gtk_label_new (_("GPS Protocol:"));
342   w->proto_b = GTK_COMBO_BOX(gtk_combo_box_new_text ());
343   gtk_combo_box_append_text (w->proto_b, "Garmin");
344   gtk_combo_box_append_text (w->proto_b, "Magellan");
345   gtk_combo_box_append_text (w->proto_b, "DeLorme");
346   gtk_combo_box_append_text (w->proto_b, "NAViLink");
347   gtk_combo_box_set_active (w->proto_b, 0);
348   g_object_ref(w->proto_b);
349
350   w->ser_l = gtk_label_new (_("Serial Port:"));
351   w->ser_b = GTK_COMBO_BOX(gtk_combo_box_entry_new_text ());
352 #ifdef WINDOWS
353   gtk_combo_box_append_text (w->ser_b, "com1");
354 #else
355   /* Here just try to see if the device is available which gets passed onto gpsbabel
356      List USB devices first as these will generally only be present if autogenerated by udev or similar
357      User is still able to set their own free text entry */
358   if (g_access ("/dev/ttyUSB0", R_OK) == 0)
359     gtk_combo_box_append_text (w->ser_b, "/dev/ttyUSB0");
360   if (g_access ("/dev/ttyUSB1", R_OK) == 0)
361     gtk_combo_box_append_text (w->ser_b, "/dev/ttyUSB1");
362   if (g_access ("/dev/ttyS0", R_OK) == 0)
363     gtk_combo_box_append_text (w->ser_b, "/dev/ttyS0");
364   if (g_access ("/dev/ttyS1", R_OK) == 0)
365     gtk_combo_box_append_text (w->ser_b, "/dev/ttyS1");
366 #endif
367   gtk_combo_box_append_text (w->ser_b, "usb:");
368   gtk_combo_box_set_active (w->ser_b, 0);
369   g_object_ref(w->ser_b);
370
371   w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
372   w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
373
374   box = GTK_TABLE(gtk_table_new(2, 3, FALSE));
375   gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_l), 0, 1, 0, 1);
376   gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_b), 1, 2, 0, 1);
377   gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_l), 0, 1, 1, 2);
378   gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_b), 1, 2, 1, 2);
379   gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_l), 0, 1, 2, 3);
380   gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_b), 1, 3, 2, 3);
381   gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(box), FALSE, FALSE, 5 );
382
383   gtk_widget_show_all ( dialog );
384 }
385
386 void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
387 {
388   GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel;
389
390   gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
391
392   gpslabel = gtk_label_new (_("GPS device: N/A"));
393   verlabel = gtk_label_new ("");
394   idlabel = gtk_label_new ("");
395   wplabel = gtk_label_new ("");
396   trklabel = gtk_label_new ("");
397
398   gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), gpslabel, FALSE, FALSE, 5 );
399   gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), wplabel, FALSE, FALSE, 5 );
400   gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), trklabel, FALSE, FALSE, 5 );
401
402   gtk_widget_show_all ( dialog );
403
404   w_gps->gps_label = gpslabel;
405   w_gps->id_label = idlabel;
406   w_gps->ver_label = verlabel;
407   w_gps->progress_label = w_gps->wp_label = wplabel;
408   w_gps->trk_label = trklabel;
409   w_gps->total_count = -1;
410 }