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