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