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