]> git.street.me.uk Git - andy/viking.git/blame - src/datasource_gps.c
Allow statusbar update signal method to specify which part of the statusbar to update.
[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
40static gboolean gps_acquire_in_progress = FALSE;
41
3f6db253 42static gint last_active = -1;
7f23d292
RN
43static gboolean last_get_tracks = TRUE;
44static gboolean last_get_waypoints = TRUE;
8627bd99 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,
0944940f 66 (VikDataSourceProcessFunc) NULL,
7b3479e3
EB
67 (VikDataSourceProgressFunc) datasource_gps_progress,
68 (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
2b756ea0
RN
69 (VikDataSourceCleanupFunc) datasource_gps_cleanup,
70 (VikDataSourceOffFunc) datasource_gps_off
7b3479e3
EB
71};
72
73/*********************************************************
74 * Definitions and routines for acquiring data from GPS
75 *********************************************************/
76
65f0ccab 77/* widgets in setup dialog specific to GPS */
7b3479e3
EB
78/* widgets in progress dialog specific to GPS */
79/* also counts needed for progress */
80typedef struct {
65f0ccab
AF
81 /* setup dialog */
82 GtkWidget *proto_l;
83 GtkComboBox *proto_b;
84 GtkWidget *ser_l;
85 GtkComboBox *ser_b;
2b756ea0
RN
86 GtkWidget *off_request_l;
87 GtkCheckButton *off_request_b;
d6c58ab9
RN
88 GtkWidget *get_tracks_l;
89 GtkCheckButton *get_tracks_b;
90 GtkWidget *get_waypoints_l;
91 GtkCheckButton *get_waypoints_b;
65f0ccab
AF
92
93 /* progress dialog */
7b3479e3
EB
94 GtkWidget *gps_label;
95 GtkWidget *ver_label;
96 GtkWidget *id_label;
97 GtkWidget *wp_label;
98 GtkWidget *trk_label;
99 GtkWidget *progress_label;
65f0ccab
AF
100
101 /* state */
7b3479e3
EB
102 int total_count;
103 int count;
65f0ccab
AF
104} gps_user_data_t;
105
106static gpointer datasource_gps_init_func ()
107{
108 return g_malloc (sizeof(gps_user_data_t));
109}
7b3479e3 110
65f0ccab 111static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelargs, gchar **input_file )
7b3479e3 112{
cf7fdc15
GB
113 char *ser = NULL;
114 char *device = NULL;
d6c58ab9
RN
115 char *tracks = NULL;
116 char *waypoints = NULL;
65f0ccab
AF
117 gps_user_data_t *w = (gps_user_data_t *)user_data;
118
7b3479e3
EB
119 if (gps_acquire_in_progress) {
120 *babelargs = *input_file = NULL;
121 }
65f0ccab
AF
122
123 gps_acquire_in_progress = TRUE;
124
8627bd99 125 last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
78f6c63d
RN
126 if (a_babel_device_list)
127 device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
2b756ea0 128
7f23d292
RN
129 last_get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
130 if (last_get_tracks)
d6c58ab9
RN
131 tracks = "-t";
132 else
133 tracks = "";
7f23d292
RN
134 last_get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
135 if (last_get_waypoints)
d6c58ab9
RN
136 waypoints = "-w";
137 else
138 waypoints = "";
139
140 *babelargs = g_strdup_printf("-D 9 %s %s -i %s", tracks, waypoints, device);
cf7fdc15
GB
141 /* device points to static content => no free */
142 device = NULL;
d6c58ab9
RN
143 tracks = NULL;
144 waypoints = NULL;
145
cf7fdc15 146 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
cf7fdc15 147 *input_file = g_strdup(ser);
7b3479e3 148
4c77d5e0 149 g_debug(_("using cmdline '%s' and file '%s'\n"), *babelargs, *input_file);
7b3479e3
EB
150}
151
2b756ea0
RN
152
153static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **input_file )
154{
2b756ea0
RN
155 char *ser = NULL;
156 char *device = NULL;
2b756ea0
RN
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
78f6c63d
RN
168 if (!a_babel_device_list)
169 return;
8627bd99
GB
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")) {
2b756ea0 173 device = "garmin,power_off";
4136d029 174 }
8627bd99 175 else if (!strcmp(device, "navilink")) {
4136d029
RN
176 device = "navilink,power_off";
177 }
178 else {
2b756ea0
RN
179 return;
180 }
181
182 *babelargs = g_strdup_printf("-i %s", device);
183 /* device points to static content => no free */
184 device = NULL;
185
2b756ea0 186 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
2b756ea0
RN
187 *input_file = g_strdup(ser);
188}
189
190
65f0ccab 191static void datasource_gps_cleanup ( gpointer user_data )
7b3479e3 192{
65f0ccab 193 g_free ( user_data );
7b3479e3
EB
194 gps_acquire_in_progress = FALSE;
195}
196
197static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
198{
cf7fdc15 199 gchar *s = NULL;
7b3479e3
EB
200 gdk_threads_enter();
201 if (w->ok) {
65f0ccab 202 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
97634600
GB
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);
7b3479e3
EB
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 }
cf7fdc15 213 g_free(s); s = NULL;
7b3479e3
EB
214 gdk_threads_leave();
215}
216
217static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
218{
cf7fdc15 219 gchar *s = NULL;
7b3479e3
EB
220 gdk_threads_enter();
221 if (w->ok) {
65f0ccab 222 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
7b3479e3
EB
223
224 if (cnt < gps_data->total_count) {
4c77d5e0 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");
7b3479e3 226 } else {
4c77d5e0 227 s = g_strdup_printf(_("Downloaded %d %s."), cnt, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
7b3479e3
EB
228 }
229 gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
230 }
cf7fdc15 231 g_free(s); s = NULL;
7b3479e3
EB
232 gdk_threads_leave();
233}
234
235static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
236{
cf7fdc15 237 gchar *s = NULL;
7b3479e3
EB
238 gdk_threads_enter();
239 if (w->ok) {
4c77d5e0 240 s = g_strdup_printf(_("GPS Device: %s"), info);
65f0ccab 241 gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
7b3479e3 242 }
cf7fdc15 243 g_free(s); s = NULL;
7b3479e3
EB
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 */
252static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
253{
254 gchar *line;
65f0ccab 255 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
7b3479e3 256
7b3479e3
EB
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;
c83b5ad9
QT
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);
7b3479e3 286 }
c83b5ad9 287 g_strfreev(tokens);
7b3479e3 288 }
0a3f9142
RN
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 }
7b3479e3
EB
301 if (strstr(line, "RECORD")) {
302 int lsb, msb, cnt;
303
c83b5ad9
QT
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 }
7b3479e3
EB
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
8627bd99
GB
324void 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
3f6db253
RN
331static gint find_entry = -1;
332static gint garmin_entry = -1;
333
334static 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
65f0ccab
AF
343void 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;
d6c58ab9 346 GtkTable *box, *data_type_box;
65f0ccab 347
4c77d5e0 348 w->proto_l = gtk_label_new (_("GPS Protocol:"));
65f0ccab 349 w->proto_b = GTK_COMBO_BOX(gtk_combo_box_new_text ());
8627bd99 350 g_list_foreach (a_babel_device_list, append_element, w->proto_b);
3f6db253
RN
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
8627bd99 364 gtk_combo_box_set_active (w->proto_b, last_active);
65f0ccab
AF
365 g_object_ref(w->proto_b);
366
4c77d5e0 367 w->ser_l = gtk_label_new (_("Serial Port:"));
65f0ccab 368 w->ser_b = GTK_COMBO_BOX(gtk_combo_box_entry_new_text ());
8d70f073
MA
369#ifdef WINDOWS
370 gtk_combo_box_append_text (w->ser_b, "com1");
371#else
99163c34
RN
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");
8d70f073 383#endif
7963d365 384 gtk_combo_box_append_text (w->ser_b, "usb:");
65f0ccab
AF
385 gtk_combo_box_set_active (w->ser_b, 0);
386 g_object_ref(w->ser_b);
387
4136d029 388 w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
2b756ea0
RN
389 w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
390
d6c58ab9
RN
391 w->get_tracks_l = gtk_label_new (_("Tracks:"));
392 w->get_tracks_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
7f23d292 393 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), last_get_tracks);
d6c58ab9
RN
394
395 w->get_waypoints_l = gtk_label_new (_("Waypoints:"));
396 w->get_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
7f23d292 397 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), last_get_waypoints);
d6c58ab9
RN
398
399 box = GTK_TABLE(gtk_table_new(2, 4, FALSE));
400 data_type_box = GTK_TABLE(gtk_table_new(4, 1, FALSE));
401
65f0ccab
AF
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);
d6c58ab9
RN
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);
65f0ccab
AF
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
418void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
7b3479e3
EB
419{
420 GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel;
421
65f0ccab 422 gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
7b3479e3 423
4c77d5e0 424 gpslabel = gtk_label_new (_("GPS device: N/A"));
7b3479e3
EB
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
7b3479e3
EB
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;
7b3479e3 442}