]> git.street.me.uk Git - andy/viking.git/blame - src/datasource_gps.c
Fix: background calling code should control return value
[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
65f0ccab 46static gpointer datasource_gps_init_func ( );
7b3479e3 47static void datasource_gps_get_cmd_string ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
65f0ccab 48static void datasource_gps_cleanup ( gpointer user_data );
7b3479e3 49static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
65f0ccab
AF
50static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
51static void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data );
2b756ea0 52static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
7b3479e3
EB
53
54VikDataSourceInterface vik_datasource_gps_interface = {
4c77d5e0
GB
55 N_("Acquire from GPS"),
56 N_("Acquired from GPS"),
7b3479e3 57 VIK_DATASOURCE_GPSBABEL_DIRECT,
805d282e 58 VIK_DATASOURCE_CREATENEWLAYER,
28c82d8b
EB
59 VIK_DATASOURCE_INPUTTYPE_NONE,
60 TRUE,
d2525524 61 TRUE,
65f0ccab 62 (VikDataSourceInitFunc) datasource_gps_init_func,
92255687 63 (VikDataSourceCheckExistenceFunc) NULL,
65f0ccab 64 (VikDataSourceAddSetupWidgetsFunc) datasource_gps_add_setup_widgets,
7b3479e3 65 (VikDataSourceGetCmdStringFunc) datasource_gps_get_cmd_string,
7b3479e3
EB
66 (VikDataSourceProgressFunc) datasource_gps_progress,
67 (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
2b756ea0
RN
68 (VikDataSourceCleanupFunc) datasource_gps_cleanup,
69 (VikDataSourceOffFunc) datasource_gps_off
7b3479e3
EB
70};
71
72/*********************************************************
73 * Definitions and routines for acquiring data from GPS
74 *********************************************************/
75
65f0ccab 76/* widgets in setup dialog specific to GPS */
7b3479e3
EB
77/* widgets in progress dialog specific to GPS */
78/* also counts needed for progress */
79typedef struct {
65f0ccab
AF
80 /* setup dialog */
81 GtkWidget *proto_l;
82 GtkComboBox *proto_b;
83 GtkWidget *ser_l;
84 GtkComboBox *ser_b;
2b756ea0
RN
85 GtkWidget *off_request_l;
86 GtkCheckButton *off_request_b;
65f0ccab
AF
87
88 /* progress dialog */
7b3479e3
EB
89 GtkWidget *gps_label;
90 GtkWidget *ver_label;
91 GtkWidget *id_label;
92 GtkWidget *wp_label;
93 GtkWidget *trk_label;
94 GtkWidget *progress_label;
65f0ccab
AF
95
96 /* state */
7b3479e3
EB
97 int total_count;
98 int count;
65f0ccab
AF
99} gps_user_data_t;
100
101static gpointer datasource_gps_init_func ()
102{
103 return g_malloc (sizeof(gps_user_data_t));
104}
7b3479e3 105
65f0ccab 106static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelargs, gchar **input_file )
7b3479e3 107{
cf7fdc15
GB
108 char *proto = NULL;
109 char *ser = NULL;
110 char *device = NULL;
1a8437ab 111#ifndef USE_NEW_COMBO_BOX
f3f1fa6c 112 GtkTreeIter iter;
1a8437ab 113#endif
65f0ccab
AF
114 gps_user_data_t *w = (gps_user_data_t *)user_data;
115
7b3479e3
EB
116 if (gps_acquire_in_progress) {
117 *babelargs = *input_file = NULL;
118 }
65f0ccab
AF
119
120 gps_acquire_in_progress = TRUE;
121
1a8437ab 122#ifdef USE_NEW_COMBO_BOX
cf7fdc15 123 proto = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->proto_b));
1a8437ab 124#else
cf7fdc15 125 proto = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->proto_b),&iter);
1a8437ab 126#endif
cf7fdc15
GB
127 if (!strcmp(proto, "Garmin")) {
128 device = "garmin";
ad606d98 129 } else if (!strcmp(proto, "Magellan")) {
cf7fdc15 130 device = "magellan";
65f0ccab 131 }
4136d029 132 else if (!strcmp(proto, "DeLorme")) {
ad606d98
RN
133 device = "delbin";
134 }
4136d029
RN
135 else {
136 device = "navilink";
137 }
2b756ea0 138
cf7fdc15
GB
139 *babelargs = g_strdup_printf("-D 9 -t -w -i %s", device);
140 /* device points to static content => no free */
141 device = NULL;
f3f1fa6c
AF
142
143 /* Old stuff */
1a8437ab 144#ifdef USE_NEW_COMBO_BOX
cf7fdc15 145 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
1a8437ab 146#else
cf7fdc15 147 ser = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->ser_b),&iter);
1a8437ab 148#endif
cf7fdc15 149 *input_file = g_strdup(ser);
7b3479e3 150
4c77d5e0 151 g_debug(_("using cmdline '%s' and file '%s'\n"), *babelargs, *input_file);
7b3479e3
EB
152}
153
2b756ea0
RN
154
155static 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";
4136d029
RN
181 }
182 else if (!strcmp(proto, "NAViLink")) {
183 device = "navilink,power_off";
184 }
185 else {
2b756ea0
RN
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
65f0ccab 203static void datasource_gps_cleanup ( gpointer user_data )
7b3479e3 204{
65f0ccab 205 g_free ( user_data );
7b3479e3
EB
206 gps_acquire_in_progress = FALSE;
207}
208
209static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
210{
cf7fdc15 211 gchar *s = NULL;
7b3479e3
EB
212 gdk_threads_enter();
213 if (w->ok) {
65f0ccab 214 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
97634600
GB
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);
7b3479e3
EB
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 }
cf7fdc15 225 g_free(s); s = NULL;
7b3479e3
EB
226 gdk_threads_leave();
227}
228
229static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
230{
cf7fdc15 231 gchar *s = NULL;
7b3479e3
EB
232 gdk_threads_enter();
233 if (w->ok) {
65f0ccab 234 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
7b3479e3
EB
235
236 if (cnt < gps_data->total_count) {
4c77d5e0 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");
7b3479e3 238 } else {
4c77d5e0 239 s = g_strdup_printf(_("Downloaded %d %s."), cnt, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
7b3479e3
EB
240 }
241 gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
242 }
cf7fdc15 243 g_free(s); s = NULL;
7b3479e3
EB
244 gdk_threads_leave();
245}
246
247static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
248{
cf7fdc15 249 gchar *s = NULL;
7b3479e3
EB
250 gdk_threads_enter();
251 if (w->ok) {
4c77d5e0 252 s = g_strdup_printf(_("GPS Device: %s"), info);
65f0ccab 253 gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
7b3479e3 254 }
cf7fdc15 255 g_free(s); s = NULL;
7b3479e3
EB
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 */
264static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
265{
266 gchar *line;
65f0ccab 267 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
7b3479e3 268
7b3479e3
EB
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;
c83b5ad9
QT
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);
7b3479e3 298 }
c83b5ad9 299 g_strfreev(tokens);
7b3479e3 300 }
0a3f9142
RN
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 }
7b3479e3
EB
313 if (strstr(line, "RECORD")) {
314 int lsb, msb, cnt;
315
c83b5ad9
QT
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 }
7b3479e3
EB
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
65f0ccab
AF
336void 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
4c77d5e0 341 w->proto_l = gtk_label_new (_("GPS Protocol:"));
65f0ccab
AF
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");
ad606d98 345 gtk_combo_box_append_text (w->proto_b, "DeLorme");
4136d029 346 gtk_combo_box_append_text (w->proto_b, "NAViLink");
65f0ccab
AF
347 gtk_combo_box_set_active (w->proto_b, 0);
348 g_object_ref(w->proto_b);
349
4c77d5e0 350 w->ser_l = gtk_label_new (_("Serial Port:"));
65f0ccab 351 w->ser_b = GTK_COMBO_BOX(gtk_combo_box_entry_new_text ());
8d70f073
MA
352#ifdef WINDOWS
353 gtk_combo_box_append_text (w->ser_b, "com1");
354#else
99163c34
RN
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");
8d70f073 366#endif
7963d365 367 gtk_combo_box_append_text (w->ser_b, "usb:");
65f0ccab
AF
368 gtk_combo_box_set_active (w->ser_b, 0);
369 g_object_ref(w->ser_b);
370
4136d029 371 w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
2b756ea0
RN
372 w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
373
374 box = GTK_TABLE(gtk_table_new(2, 3, FALSE));
65f0ccab
AF
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);
2b756ea0
RN
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);
65f0ccab
AF
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
386void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
7b3479e3
EB
387{
388 GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel;
389
65f0ccab 390 gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
7b3479e3 391
4c77d5e0 392 gpslabel = gtk_label_new (_("GPS device: N/A"));
7b3479e3
EB
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
7b3479e3
EB
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;
7b3479e3 410}