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