]> git.street.me.uk Git - andy/viking.git/blame - src/datasource_gps.c
Embed GtkHTML 4.10.0 URI functions
[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 5 * Copyright (C) 2006, Alex Foobarian <foobarian@gmail.com>
17acdaec 6 * Copyright (C) 2012-2015, 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 34
d80e59ba 35#include "datasource_gps.h"
7b3479e3
EB
36#include "viking.h"
37#include "babel.h"
38#include "gpx.h"
39#include "acquire.h"
40
41static gboolean gps_acquire_in_progress = FALSE;
42
3f6db253 43static gint last_active = -1;
8627bd99 44
307abf54 45static gpointer datasource_gps_init_func ( acq_vik_t *avt );
17acdaec 46static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 );
65f0ccab 47static void datasource_gps_cleanup ( gpointer user_data );
7b3479e3 48static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
65f0ccab
AF
49static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
50static void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data );
2b756ea0 51static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
7b3479e3
EB
52
53VikDataSourceInterface vik_datasource_gps_interface = {
4c77d5e0
GB
54 N_("Acquire from GPS"),
55 N_("Acquired from GPS"),
9cc13848 56 VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT,
28c82d8b
EB
57 VIK_DATASOURCE_INPUTTYPE_NONE,
58 TRUE,
d2525524 59 TRUE,
b2aa700f 60 TRUE,
65f0ccab 61 (VikDataSourceInitFunc) datasource_gps_init_func,
92255687 62 (VikDataSourceCheckExistenceFunc) NULL,
65f0ccab 63 (VikDataSourceAddSetupWidgetsFunc) datasource_gps_add_setup_widgets,
17acdaec
RN
64 (VikDataSourceGetProcessOptionsFunc) datasource_gps_get_process_options,
65 (VikDataSourceProcessFunc) a_babel_convert_from,
7b3479e3
EB
66 (VikDataSourceProgressFunc) datasource_gps_progress,
67 (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
2b756ea0 68 (VikDataSourceCleanupFunc) datasource_gps_cleanup,
63959706
RN
69 (VikDataSourceOffFunc) datasource_gps_off,
70
71 NULL,
72 0,
73 NULL,
74 NULL,
75 0
7b3479e3
EB
76};
77
78/*********************************************************
79 * Definitions and routines for acquiring data from GPS
80 *********************************************************/
81
65f0ccab 82/* widgets in setup dialog specific to GPS */
7b3479e3
EB
83/* widgets in progress dialog specific to GPS */
84/* also counts needed for progress */
85typedef struct {
65f0ccab
AF
86 /* setup dialog */
87 GtkWidget *proto_l;
1bc1c05b 88 GtkWidget *proto_b;
65f0ccab 89 GtkWidget *ser_l;
1bc1c05b 90 GtkWidget *ser_b;
2b756ea0
RN
91 GtkWidget *off_request_l;
92 GtkCheckButton *off_request_b;
d6c58ab9
RN
93 GtkWidget *get_tracks_l;
94 GtkCheckButton *get_tracks_b;
0d2b891f
RN
95 GtkWidget *get_routes_l;
96 GtkCheckButton *get_routes_b;
d6c58ab9
RN
97 GtkWidget *get_waypoints_l;
98 GtkCheckButton *get_waypoints_b;
65f0ccab
AF
99
100 /* progress dialog */
7b3479e3 101 GtkWidget *gps_label;
d3b7baa7 102 GtkWidget *wpt_label;
7b3479e3 103 GtkWidget *trk_label;
0d2b891f 104 GtkWidget *rte_label;
0d2b891f 105 vik_gps_xfer_type progress_type;
65f0ccab 106
d3b7baa7
RN
107 // Maintain separate counts for each type
108 int wpt_total_count;
109 int wpt_count;
110 int trk_total_count;
111 int trk_count;
112 int rte_total_count;
113 int rte_count;
114 gchar *info;
aa6dfd27
RN
115 // Know which way xfer is so xfer setting types are only stored for download
116 vik_gps_dir direction;
d3b7baa7
RN
117 // GUI Updates
118 gint id_status;
119 gint id_info;
120 gint id_total_count;
121 gint id_count;
65f0ccab
AF
122} gps_user_data_t;
123
aa6dfd27
RN
124#define VIK_SETTINGS_GPS_GET_TRACKS "gps_download_tracks"
125#define VIK_SETTINGS_GPS_GET_ROUTES "gps_download_routes"
126#define VIK_SETTINGS_GPS_GET_WAYPOINTS "gps_download_waypoints"
127#define VIK_SETTINGS_GPS_PROTOCOL "gps_protocol"
128#define VIK_SETTINGS_GPS_PORT "gps_port"
129#define VIK_SETTINGS_GPS_POWER_OFF "gps_power_off"
130
307abf54 131static gpointer datasource_gps_init_func ( acq_vik_t *avt )
65f0ccab 132{
d3b7baa7 133 gps_user_data_t *gps_ud = g_malloc0 (sizeof(gps_user_data_t));
aa6dfd27
RN
134 gps_ud->direction = GPS_DOWN;
135 return gps_ud;
65f0ccab 136}
7b3479e3 137
d80e59ba
RN
138/**
139 * datasource_gps_get_protocol:
140 *
141 * Method to get the communication protocol of the GPS device from the widget structure
142 */
143gchar* datasource_gps_get_protocol ( gpointer user_data )
144{
145 // Uses the list of supported devices
146 gps_user_data_t *w = (gps_user_data_t *)user_data;
147 last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
aa6dfd27
RN
148 if (a_babel_device_list) {
149 gchar *protocol = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
150 a_settings_set_string ( VIK_SETTINGS_GPS_PROTOCOL, protocol );
151 return protocol;
152 }
d80e59ba
RN
153
154 return NULL;
155}
156
157/**
158 * datasource_gps_get_descriptor:
159 *
160 * Method to get the descriptor from the widget structure
161 * "Everything is a file"
162 * Could actually be normal file or a serial port
163 */
164gchar* datasource_gps_get_descriptor ( gpointer user_data )
165{
166 gps_user_data_t *w = (gps_user_data_t *)user_data;
1bc1c05b
RN
167
168#if GTK_CHECK_VERSION (2, 24, 0)
aa6dfd27 169 gchar *descriptor = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
1bc1c05b 170#else
aa6dfd27 171 gchar *descriptor = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
1bc1c05b 172#endif
aa6dfd27
RN
173 a_settings_set_string ( VIK_SETTINGS_GPS_PORT, descriptor );
174 return descriptor;
d80e59ba
RN
175}
176
177/**
178 * datasource_gps_get_do_tracks:
179 *
180 * Method to get the track handling behaviour from the widget structure
181 */
182gboolean datasource_gps_get_do_tracks ( gpointer user_data )
183{
184 gps_user_data_t *w = (gps_user_data_t *)user_data;
aa6dfd27
RN
185 gboolean get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
186 if ( w->direction == GPS_DOWN )
187 a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, get_tracks );
188 return get_tracks;
d80e59ba
RN
189}
190
0d2b891f
RN
191/**
192 * datasource_gps_get_do_routes:
193 *
194 * Method to get the route handling behaviour from the widget structure
195 */
196gboolean datasource_gps_get_do_routes ( gpointer user_data )
197{
198 gps_user_data_t *w = (gps_user_data_t *)user_data;
aa6dfd27
RN
199 gboolean get_routes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_routes_b));
200 if ( w->direction == GPS_DOWN )
201 a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, get_routes );
202 return get_routes;
0d2b891f
RN
203}
204
d80e59ba
RN
205/**
206 * datasource_gps_get_do_waypoints:
207 *
208 * Method to get the waypoint handling behaviour from the widget structure
209 */
210gboolean datasource_gps_get_do_waypoints ( gpointer user_data )
211{
212 gps_user_data_t *w = (gps_user_data_t *)user_data;
aa6dfd27
RN
213 gboolean get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
214 if ( w->direction == GPS_DOWN )
215 a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, get_waypoints );
216 return get_waypoints;
d80e59ba
RN
217}
218
17acdaec 219static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 )
7b3479e3 220{
cf7fdc15 221 char *device = NULL;
d6c58ab9 222 char *tracks = NULL;
0d2b891f 223 char *routes = NULL;
d6c58ab9 224 char *waypoints = NULL;
65f0ccab 225
7b3479e3 226 if (gps_acquire_in_progress) {
17acdaec 227 po->babelargs = po->filename = NULL;
7b3479e3 228 }
65f0ccab
AF
229
230 gps_acquire_in_progress = TRUE;
231
d80e59ba 232 device = datasource_gps_get_protocol ( user_data );
2b756ea0 233
d80e59ba 234 if ( datasource_gps_get_do_tracks ( user_data ) )
d6c58ab9
RN
235 tracks = "-t";
236 else
237 tracks = "";
d80e59ba 238
0d2b891f
RN
239 if ( datasource_gps_get_do_routes ( user_data ) )
240 routes = "-r";
241 else
242 routes = "";
243
d80e59ba 244 if ( datasource_gps_get_do_waypoints ( user_data ) )
d6c58ab9
RN
245 waypoints = "-w";
246 else
247 waypoints = "";
248
17acdaec 249 po->babelargs = g_strdup_printf("-D 9 %s %s %s -i %s", tracks, routes, waypoints, device);
cf7fdc15
GB
250 /* device points to static content => no free */
251 device = NULL;
d6c58ab9 252 tracks = NULL;
0d2b891f 253 routes = NULL;
d6c58ab9
RN
254 waypoints = NULL;
255
17acdaec 256 po->filename = g_strdup(datasource_gps_get_descriptor(user_data));
7b3479e3 257
17acdaec 258 g_debug(_("using cmd '%s' and file '%s'\n"), po->babelargs, po->filename);
7b3479e3
EB
259}
260
d80e59ba
RN
261/**
262 * datasource_gps_get_off:
263 *
264 * Method to get the off behaviour from the widget structure
265 */
266gboolean datasource_gps_get_off ( gpointer user_data )
267{
268 gps_user_data_t *w = (gps_user_data_t *)user_data;
aa6dfd27
RN
269 gboolean power_off = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b));
270 a_settings_set_boolean ( VIK_SETTINGS_GPS_POWER_OFF, power_off );
271 return power_off;
d80e59ba 272}
2b756ea0 273
17acdaec 274static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **file_descriptor )
2b756ea0 275{
2b756ea0
RN
276 char *ser = NULL;
277 char *device = NULL;
2b756ea0
RN
278 gps_user_data_t *w = (gps_user_data_t *)user_data;
279
280 if (gps_acquire_in_progress) {
17acdaec 281 *babelargs = *file_descriptor = NULL;
2b756ea0
RN
282 }
283
284 /* See if we should turn off the device */
d80e59ba 285 if (!datasource_gps_get_off ( user_data )){
2b756ea0
RN
286 return;
287 }
288
78f6c63d
RN
289 if (!a_babel_device_list)
290 return;
8627bd99
GB
291 last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
292 device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
293 if (!strcmp(device, "garmin")) {
2b756ea0 294 device = "garmin,power_off";
4136d029 295 }
8627bd99 296 else if (!strcmp(device, "navilink")) {
4136d029
RN
297 device = "navilink,power_off";
298 }
299 else {
2b756ea0
RN
300 return;
301 }
302
303 *babelargs = g_strdup_printf("-i %s", device);
304 /* device points to static content => no free */
305 device = NULL;
306
1bc1c05b
RN
307#if GTK_CHECK_VERSION (2, 24, 0)
308 ser = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
309#else
2b756ea0 310 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
1bc1c05b 311#endif
17acdaec 312 *file_descriptor = g_strdup(ser);
2b756ea0
RN
313}
314
315
65f0ccab 316static void datasource_gps_cleanup ( gpointer user_data )
7b3479e3 317{
d3b7baa7
RN
318 gps_user_data_t *gud = (gps_user_data_t *)user_data;
319 // Remove any outstanding GUI update requests
320 if ( gud->id_status )
321 g_source_remove ( gud->id_status );
322 if ( gud->id_info )
323 g_source_remove ( gud->id_info );
324 if ( gud->id_total_count )
325 g_source_remove ( gud->id_total_count );
326 if ( gud->id_count )
327 g_source_remove ( gud->id_count );
328 g_free ( gud->info );
329 g_free ( gud );
7b3479e3
EB
330 gps_acquire_in_progress = FALSE;
331}
332
d80e59ba
RN
333/**
334 * datasource_gps_clean_up:
335 *
336 * External method to tidy up
337 */
338void datasource_gps_clean_up ( gpointer user_data )
339{
340 datasource_gps_cleanup ( user_data );
341}
342
d3b7baa7 343static gboolean show_total_count(acq_dialog_widgets_t *w)
7b3479e3 344{
d3b7baa7 345 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
b2aa700f 346 if (w->running) {
d3b7baa7
RN
347 gint tmp_count;
348 GtkWidget *progress_label;
97634600 349 const gchar *tmp_str;
0d2b891f 350 switch (gps_data->progress_type) {
d3b7baa7
RN
351 case WPT:
352 progress_label = gps_data->wpt_label;
353 tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", gps_data->wpt_total_count);
354 tmp_count = gps_data->wpt_total_count;
355 break;
356 case TRK:
357 progress_label = gps_data->trk_label;
358 tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", gps_data->trk_total_count);
359 tmp_count = gps_data->trk_total_count;
360 break;
0d2b891f 361 default:
d3b7baa7
RN
362 progress_label = gps_data->rte_label;
363 tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", gps_data->rte_total_count);
364 tmp_count = gps_data->rte_total_count;
365 break;
0d2b891f 366 }
d3b7baa7
RN
367 gchar *s = g_strdup_printf(tmp_str, tmp_count);
368 gtk_label_set_text ( GTK_LABEL(progress_label), s );
369 gtk_widget_show ( progress_label );
370 g_free(s);
7b3479e3 371 }
d3b7baa7
RN
372 gps_data->id_total_count = 0;
373 return FALSE;
7b3479e3
EB
374}
375
d3b7baa7 376static gboolean show_current_count(acq_dialog_widgets_t *w)
7b3479e3 377{
d3b7baa7 378 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
b2aa700f 379 if (w->running) {
d3b7baa7
RN
380 GtkWidget *progress_label;
381 gchar *s = NULL;
382 switch (gps_data->progress_type) {
383 case WPT:
384 progress_label = gps_data->wpt_label;
385 if ( gps_data->wpt_count < gps_data->wpt_total_count )
386 s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->wpt_count, gps_data->wpt_total_count, "waypoints");
387 else
388 s = g_strdup_printf(_("Downloaded %d %s."), gps_data->wpt_count, "waypoints");
389 break;
390 case TRK:
391 progress_label = gps_data->trk_label;
392 if ( gps_data->trk_count < gps_data->trk_total_count )
393 s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->trk_count, gps_data->trk_total_count, "trackpoints");
394 else
395 s = g_strdup_printf(_("Downloaded %d %s."), gps_data->trk_count, "trackpoints");
396 break;
397 default:
398 progress_label = gps_data->rte_label;
399 if ( gps_data->rte_count < gps_data->rte_total_count )
400 s = g_strdup_printf(_("Downloaded %d out of %d %s..."), gps_data->rte_count, gps_data->rte_total_count, "routepoints");
401 else
402 s = g_strdup_printf(_("Downloaded %d %s."), gps_data->rte_count, "routepoints");
403 break;
0d2b891f 404 }
d3b7baa7
RN
405 gtk_label_set_text ( GTK_LABEL(progress_label), s );
406 g_free(s);
407 }
408 gps_data->id_count = 0;
409 return FALSE;
410}
411
412static gboolean show_gps_info(acq_dialog_widgets_t *w)
413{
414 gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
415 if (w->running) {
416 gchar *s = g_strdup_printf ( _("GPS Device: %s"), gps_data->info );
417 gtk_label_set_text ( GTK_LABEL(gps_data->gps_label), s );
418 g_free(s);
7b3479e3 419 }
d3b7baa7
RN
420 gps_data->id_info = 0;
421 return FALSE;
7b3479e3
EB
422}
423
d3b7baa7 424static gboolean show_gps_status(acq_dialog_widgets_t *w)
7b3479e3 425{
d3b7baa7 426 gps_user_data_t *gps_data = (gps_user_data_t*)w->user_data;
b2aa700f 427 if (w->running) {
d3b7baa7 428 gtk_label_set_text ( GTK_LABEL(w->status), _("Status: Working...") );
7b3479e3 429 }
d3b7baa7
RN
430 gps_data->id_status = 0;
431 return FALSE;
7b3479e3
EB
432}
433
434/*
435 * This routine relies on gpsbabel's diagnostic output to display the progress information.
436 * These outputs differ when different GPS devices are used, so we will need to test
437 * them on several and add the corresponding support.
438 */
439static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
440{
441 gchar *line;
65f0ccab 442 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
7b3479e3 443
7b3479e3
EB
444 switch(c) {
445 case BABEL_DIAG_OUTPUT:
446 line = (gchar *)data;
447
d3b7baa7 448 gps_data->id_status = gdk_threads_add_idle ( (GSourceFunc)show_gps_status, w );
8d0586c6 449
0d2b891f
RN
450 /* tells us the type of items that will follow */
451 if (strstr(line, "Xfer Wpt")) {
0d2b891f 452 gps_data->progress_type = WPT;
7b3479e3 453 }
0d2b891f 454 if (strstr(line, "Xfer Trk")) {
0d2b891f
RN
455 gps_data->progress_type = TRK;
456 }
457 if (strstr(line, "Xfer Rte")) {
0d2b891f 458 gps_data->progress_type = RTE;
7b3479e3 459 }
0d2b891f 460
7b3479e3
EB
461 if (strstr(line, "PRDDAT")) {
462 gchar **tokens = g_strsplit(line, " ", 0);
463 gchar info[128];
464 int ilen = 0;
465 int i;
c83b5ad9
QT
466 int n_tokens = 0;
467
468 while (tokens[n_tokens])
469 n_tokens++;
470
471 if (n_tokens > 8) {
472 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
473 guint ch;
474 sscanf(tokens[i], "%x", &ch);
475 info[ilen++] = ch;
476 }
477 info[ilen++] = 0;
d3b7baa7
RN
478 gps_data->info = g_strdup (info);
479 gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
7b3479e3 480 }
c83b5ad9 481 g_strfreev(tokens);
7b3479e3 482 }
0a3f9142
RN
483 /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
484 if (strstr(line, "Unit:")) {
485 gchar **tokens = g_strsplit(line, "\t", 0);
486 int n_tokens = 0;
487 while (tokens[n_tokens])
488 n_tokens++;
489
490 if (n_tokens > 1) {
d3b7baa7
RN
491 gps_data->info = g_strdup (tokens[1]);
492 gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
0a3f9142
RN
493 }
494 g_strfreev(tokens);
495 }
6e23e477
RN
496 /* Capture some potential errors */
497 if (strstr(line, "[ERROR] GPS")) {
498 gchar **tokens = g_strsplit(line, "\n", 0);
499 gps_data->info = g_strdup(tokens[0]);
500 gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
501 g_strfreev(tokens);
502 }
503 if (strstr(line, "an't in")) {
504 gchar **tokens = g_strsplit(line, "\n", 0);
505 gps_data->info = g_strdup(tokens[0]);
506 gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
507 g_strfreev(tokens);
508 }
509
510 if (strstr(line, "Can't get waypoint")) {
511 gchar **tokens = g_strsplit(line, "\n", 0);
512 gps_data->info = g_strdup(tokens[0]);
513 gps_data->id_info = gdk_threads_add_idle ( (GSourceFunc)show_gps_info, w );
514 g_strfreev(tokens);
515 }
0d2b891f
RN
516 /* tells us how many items there will be */
517 if (strstr(line, "RECORD")) {
7b3479e3
EB
518 int lsb, msb, cnt;
519
c83b5ad9
QT
520 if (strlen(line) > 20) {
521 sscanf(line+17, "%x", &lsb);
522 sscanf(line+20, "%x", &msb);
523 cnt = lsb + msb * 256;
d3b7baa7
RN
524 if ( gps_data->progress_type == RTE ) {
525 // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
526 gint mycnt = (cnt / 2) + 1;
527 gps_data->rte_total_count = mycnt;
528 gps_data->rte_count = 0;
529 }
530 else if ( gps_data->progress_type == TRK ) {
531 gps_data->trk_total_count = cnt;
532 gps_data->trk_count = 0;
533 }
534 else {
535 gps_data->wpt_total_count = cnt;
536 gps_data->wpt_count = 0;
537 }
538
539 gps_data->id_total_count = gdk_threads_add_idle ( (GSourceFunc)show_total_count, w);
c83b5ad9 540 }
7b3479e3 541 }
0d2b891f 542 if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
d3b7baa7
RN
543 if ( strstr(line, "WPTDAT") )
544 gps_data->wpt_count++;
545 else if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") )
546 gps_data->trk_count++;
547 else
548 // "RTEHDR" || "RTEWPT"
549 gps_data->rte_count++;
550 gps_data->id_count = gdk_threads_add_idle ( (GSourceFunc)show_current_count, w);
7b3479e3
EB
551 }
552 break;
553 case BABEL_DONE:
554 break;
555 default:
556 break;
557 }
558}
559
8627bd99
GB
560void append_element (gpointer elem, gpointer user_data)
561{
8627bd99 562 const gchar *text = ((BabelDevice*)elem)->label;
1bc1c05b 563 vik_combo_box_text_append (GTK_WIDGET(user_data), text);
8627bd99
GB
564}
565
3f6db253 566static gint find_entry = -1;
aa6dfd27 567static gint wanted_entry = -1;
3f6db253 568
aa6dfd27 569static void find_protocol (gpointer elem, gpointer user_data)
3f6db253
RN
570{
571 const gchar *name = ((BabelDevice*)elem)->name;
aa6dfd27 572 const gchar *protocol = user_data;
3f6db253 573 find_entry++;
aa6dfd27
RN
574 if (!strcmp(name, protocol)) {
575 wanted_entry = find_entry;
3f6db253
RN
576 }
577}
578
d80e59ba 579static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
65f0ccab
AF
580{
581 gps_user_data_t *w = (gps_user_data_t *)user_data;
d6c58ab9 582 GtkTable *box, *data_type_box;
65f0ccab 583
4c77d5e0 584 w->proto_l = gtk_label_new (_("GPS Protocol:"));
1bc1c05b 585 w->proto_b = vik_combo_box_text_new ();
8627bd99 586 g_list_foreach (a_babel_device_list, append_element, w->proto_b);
3f6db253 587
3f6db253
RN
588 if ( last_active < 0 ) {
589 find_entry = -1;
aa6dfd27
RN
590 wanted_entry = -1;
591 gchar *protocol = NULL;
592 if ( a_settings_get_string ( VIK_SETTINGS_GPS_PROTOCOL, &protocol ) ) {
593 // Use setting
594 if ( protocol )
595 g_list_foreach (a_babel_device_list, find_protocol, protocol);
aa6dfd27
RN
596 }
597 else {
a8ae980e 598 // Attempt to maintain default to Garmin devices (assumed most popular/numerous device)
aa6dfd27 599 g_list_foreach (a_babel_device_list, find_protocol, "garmin");
aa6dfd27 600 }
a8ae980e
RN
601 // If not found set it to the first entry, otherwise use the entry
602 last_active = ( wanted_entry < 0 ) ? 0 : wanted_entry;
3f6db253
RN
603 }
604
1bc1c05b 605 gtk_combo_box_set_active (GTK_COMBO_BOX(w->proto_b), last_active);
65f0ccab
AF
606 g_object_ref(w->proto_b);
607
4c77d5e0 608 w->ser_l = gtk_label_new (_("Serial Port:"));
1bc1c05b
RN
609#if GTK_CHECK_VERSION (2, 24, 0)
610 w->ser_b = gtk_combo_box_text_new_with_entry ();
611#else
612 w->ser_b = gtk_combo_box_entry_new_text ();
613#endif
aa6dfd27
RN
614 // Value from the settings is promoted to the top
615 gchar *gps_port = NULL;
616 if ( a_settings_get_string ( VIK_SETTINGS_GPS_PORT, &gps_port ) ) {
617 // Use setting if available
618 if ( gps_port ) {
619#ifndef WINDOWS
620 if ( !strncmp (gps_port, "/dev/tty", 6) ) {
621 if (g_access (gps_port, R_OK) == 0) {
622 vik_combo_box_text_append (w->ser_b, gps_port);
623 }
624 }
625 else
626#endif
627 vik_combo_box_text_append (w->ser_b, gps_port);
628 }
629 }
630
631 // Note avoid appending the port selected from the settings
8d70f073 632#ifdef WINDOWS
aa6dfd27
RN
633 if ( gps_port && strcmp (gps_port, "com1") )
634 vik_combo_box_text_append (w->ser_b, "com1");
8d70f073 635#else
99163c34
RN
636 /* Here just try to see if the device is available which gets passed onto gpsbabel
637 List USB devices first as these will generally only be present if autogenerated by udev or similar
638 User is still able to set their own free text entry */
aa6dfd27
RN
639 if ( gps_port && strcmp (gps_port, "/dev/ttyUSB0") )
640 if (g_access ("/dev/ttyUSB0", R_OK) == 0)
641 vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB0");
642 if ( gps_port && strcmp (gps_port, "/dev/ttyUSB1") )
643 if (g_access ("/dev/ttyUSB1", R_OK) == 0)
644 vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB1");
645 if ( gps_port && strcmp (gps_port, "/dev/ttyS0") )
646 if (g_access ("/dev/ttyS0", R_OK) == 0)
647 vik_combo_box_text_append (w->ser_b, "/dev/ttyS0");
648 if ( gps_port && strcmp (gps_port, "/dev/ttyS1") )
649 if (g_access ("/dev/ttyS1", R_OK) == 0)
650 vik_combo_box_text_append (w->ser_b, "/dev/ttyS1");
8d70f073 651#endif
aa6dfd27
RN
652 if ( gps_port && strcmp (gps_port, "usb:") )
653 vik_combo_box_text_append (w->ser_b, "usb:");
654
1bc1c05b 655 gtk_combo_box_set_active (GTK_COMBO_BOX(w->ser_b), 0);
65f0ccab
AF
656 g_object_ref(w->ser_b);
657
4136d029 658 w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
2b756ea0 659 w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
aa6dfd27
RN
660 gboolean power_off;
661 if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_POWER_OFF, &power_off ) )
662 power_off = FALSE;
663 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->off_request_b), power_off);
2b756ea0 664
d6c58ab9
RN
665 w->get_tracks_l = gtk_label_new (_("Tracks:"));
666 w->get_tracks_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
aa6dfd27
RN
667 gboolean get_tracks;
668 if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, &get_tracks ) )
669 get_tracks = TRUE;
670 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), get_tracks);
d6c58ab9 671
0d2b891f
RN
672 w->get_routes_l = gtk_label_new (_("Routes:"));
673 w->get_routes_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
aa6dfd27
RN
674 gboolean get_routes;
675 if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, &get_routes ) )
676 get_routes = FALSE;
677 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_routes_b), get_routes);
0d2b891f 678
d6c58ab9
RN
679 w->get_waypoints_l = gtk_label_new (_("Waypoints:"));
680 w->get_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
aa6dfd27
RN
681 gboolean get_waypoints;
682 if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, &get_waypoints ) )
683 get_waypoints = TRUE;
684 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), get_waypoints);
d6c58ab9
RN
685
686 box = GTK_TABLE(gtk_table_new(2, 4, FALSE));
687 data_type_box = GTK_TABLE(gtk_table_new(4, 1, FALSE));
688
65f0ccab
AF
689 gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_l), 0, 1, 0, 1);
690 gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_b), 1, 2, 0, 1);
691 gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_l), 0, 1, 1, 2);
692 gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_b), 1, 2, 1, 2);
d6c58ab9
RN
693 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_l), 0, 1, 0, 1);
694 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_b), 1, 2, 0, 1);
0d2b891f
RN
695 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_routes_l), 2, 3, 0, 1);
696 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_routes_b), 3, 4, 0, 1);
697 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_l), 4, 5, 0, 1);
698 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_b), 5, 6, 0, 1);
d6c58ab9
RN
699 gtk_table_attach_defaults(box, GTK_WIDGET(data_type_box), 0, 2, 2, 3);
700 gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_l), 0, 1, 3, 4);
701 gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_b), 1, 3, 3, 4);
9b082b39 702 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
65f0ccab
AF
703
704 gtk_widget_show_all ( dialog );
705}
706
d80e59ba
RN
707/**
708 * datasource_gps_setup:
709 * @dialog: The GTK dialog. The caller is responsible for managing the dialog creation/deletion
0d2b891f
RN
710 * @xfer: The default type of items enabled for transfer, others disabled.
711 * @xfer_all: When specified all items are enabled for transfer.
d80e59ba
RN
712 *
713 * Returns: A gpointer to the private structure for GPS progress/information widgets
714 * Pass this pointer back into the other exposed datasource_gps_X functions
715 */
0d2b891f 716gpointer datasource_gps_setup ( GtkWidget *dialog, vik_gps_xfer_type xfer, gboolean xfer_all )
d80e59ba 717{
307abf54 718 gps_user_data_t *w_gps = (gps_user_data_t *)datasource_gps_init_func ( NULL );
aa6dfd27 719 w_gps->direction = GPS_UP;
d80e59ba
RN
720 datasource_gps_add_setup_widgets ( dialog, NULL, w_gps );
721
0d2b891f
RN
722 gboolean way = xfer_all;
723 gboolean trk = xfer_all;
724 gboolean rte = xfer_all;
725
726 // Selectively turn bits on
727 if ( !xfer_all ) {
728 switch (xfer) {
729 case WPT: way = TRUE; break;
730 case RTE: rte = TRUE; break;
731 default: trk = TRUE; break;
732 }
d80e59ba 733 }
0d2b891f
RN
734
735 // Apply
736 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_tracks_b), trk );
737 gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_tracks_l), trk );
738 gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_tracks_b), trk );
739
740 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_routes_b), rte );
741 gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_routes_l), rte );
742 gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_routes_b), rte );
743
744 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_waypoints_b), way );
745 gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_waypoints_l), way );
746 gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_waypoints_b), way );
747
d80e59ba
RN
748 return (gpointer)w_gps;
749}
750
65f0ccab 751void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
7b3479e3 752{
65f0ccab 753 gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
7b3479e3 754
d3b7baa7
RN
755 w_gps->gps_label = gtk_label_new (_("GPS device: N/A"));
756 w_gps->wpt_label = gtk_label_new ("");
757 w_gps->trk_label = gtk_label_new ("");
758 w_gps->rte_label = gtk_label_new ("");
7b3479e3 759
d3b7baa7
RN
760 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->gps_label, FALSE, FALSE, 5 );
761 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->wpt_label, FALSE, FALSE, 5 );
762 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->trk_label, FALSE, FALSE, 5 );
763 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), w_gps->rte_label, FALSE, FALSE, 5 );
7b3479e3 764
7b3479e3 765 gtk_widget_show_all ( dialog );
7b3479e3 766}