2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 * Copyright (C) 2006, Alex Foobarian <foobarian@gmail.com>
6 * Copyright (C) 2010, Rob Norris <rw_norris@hotmail.com>
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.
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.
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
31 #include <glib/gstdio.h>
32 #include <glib/gprintf.h>
33 #include <glib/gi18n.h>
40 #if GTK_CHECK_VERSION(2,6,0)
41 #define USE_NEW_COMBO_BOX
44 static gboolean gps_acquire_in_progress = FALSE;
46 static gint last_active = -1;
47 static gboolean last_get_tracks = TRUE;
48 static gboolean last_get_waypoints = TRUE;
50 static gpointer datasource_gps_init_func ( );
51 static void datasource_gps_get_cmd_string ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
52 static void datasource_gps_cleanup ( gpointer user_data );
53 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
54 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
55 static void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data );
56 static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
58 VikDataSourceInterface vik_datasource_gps_interface = {
59 N_("Acquire from GPS"),
60 N_("Acquired from GPS"),
61 VIK_DATASOURCE_GPSBABEL_DIRECT,
62 VIK_DATASOURCE_CREATENEWLAYER,
63 VIK_DATASOURCE_INPUTTYPE_NONE,
66 (VikDataSourceInitFunc) datasource_gps_init_func,
67 (VikDataSourceCheckExistenceFunc) NULL,
68 (VikDataSourceAddSetupWidgetsFunc) datasource_gps_add_setup_widgets,
69 (VikDataSourceGetCmdStringFunc) datasource_gps_get_cmd_string,
70 (VikDataSourceProgressFunc) datasource_gps_progress,
71 (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
72 (VikDataSourceCleanupFunc) datasource_gps_cleanup,
73 (VikDataSourceOffFunc) datasource_gps_off
76 /*********************************************************
77 * Definitions and routines for acquiring data from GPS
78 *********************************************************/
80 /* widgets in setup dialog specific to GPS */
81 /* widgets in progress dialog specific to GPS */
82 /* also counts needed for progress */
89 GtkWidget *off_request_l;
90 GtkCheckButton *off_request_b;
91 GtkWidget *get_tracks_l;
92 GtkCheckButton *get_tracks_b;
93 GtkWidget *get_waypoints_l;
94 GtkCheckButton *get_waypoints_b;
101 GtkWidget *trk_label;
102 GtkWidget *progress_label;
109 static gpointer datasource_gps_init_func ()
111 return g_malloc (sizeof(gps_user_data_t));
114 static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelargs, gchar **input_file )
119 char *waypoints = NULL;
120 #ifndef USE_NEW_COMBO_BOX
123 gps_user_data_t *w = (gps_user_data_t *)user_data;
125 if (gps_acquire_in_progress) {
126 *babelargs = *input_file = NULL;
129 gps_acquire_in_progress = TRUE;
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;
134 last_get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
139 last_get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
140 if (last_get_waypoints)
145 *babelargs = g_strdup_printf("-D 9 %s %s -i %s", tracks, waypoints, device);
146 /* device points to static content => no free */
152 #ifdef USE_NEW_COMBO_BOX
153 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
155 ser = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->ser_b),&iter);
157 *input_file = g_strdup(ser);
159 g_debug(_("using cmdline '%s' and file '%s'\n"), *babelargs, *input_file);
163 static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **input_file )
167 #ifndef USE_NEW_COMBO_BOX
170 gps_user_data_t *w = (gps_user_data_t *)user_data;
172 if (gps_acquire_in_progress) {
173 *babelargs = *input_file = NULL;
176 /* See if we should turn off the device */
177 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b))) {
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")) {
184 device = "garmin,power_off";
186 else if (!strcmp(device, "navilink")) {
187 device = "navilink,power_off";
193 *babelargs = g_strdup_printf("-i %s", device);
194 /* device points to static content => no free */
198 #ifdef USE_NEW_COMBO_BOX
199 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
201 ser = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w->ser_b),&iter);
203 *input_file = g_strdup(ser);
207 static void datasource_gps_cleanup ( gpointer user_data )
209 g_free ( user_data );
210 gps_acquire_in_progress = FALSE;
213 static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
218 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
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);
223 tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt);
224 s = g_strdup_printf(tmp_str, cnt);
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;
233 static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
238 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
240 if (cnt < gps_data->total_count) {
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");
243 s = g_strdup_printf(_("Downloaded %d %s."), cnt, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
245 gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
251 static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
256 s = g_strdup_printf(_("GPS Device: %s"), info);
257 gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
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.
268 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
271 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
274 case BABEL_DIAG_OUTPUT:
275 line = (gchar *)data;
277 /* tells us how many items there will be */
278 if (strstr(line, "Xfer Wpt")) {
279 gps_data->progress_label = gps_data->wp_label;
281 if (strstr(line, "Xfer Trk")) {
282 gps_data->progress_label = gps_data->trk_label;
284 if (strstr(line, "PRDDAT")) {
285 gchar **tokens = g_strsplit(line, " ", 0);
291 while (tokens[n_tokens])
295 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
297 sscanf(tokens[i], "%x", &ch);
301 set_gps_info(info, w);
305 /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
306 if (strstr(line, "Unit:")) {
307 gchar **tokens = g_strsplit(line, "\t", 0);
309 while (tokens[n_tokens])
313 set_gps_info(tokens[1], w);
317 if (strstr(line, "RECORD")) {
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);
328 if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
330 set_current_count(gps_data->count, w);
340 void append_element (gpointer elem, gpointer user_data)
342 GtkComboBox *combo = GTK_COMBO_BOX (user_data);
343 const gchar *text = ((BabelDevice*)elem)->label;
344 gtk_combo_box_append_text (combo, text);
347 static gint find_entry = -1;
348 static gint garmin_entry = -1;
350 static void find_garmin (gpointer elem, gpointer user_data)
352 const gchar *name = ((BabelDevice*)elem)->name;
354 if (!strcmp(name, "garmin")) {
355 garmin_entry = find_entry;
359 void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
361 gps_user_data_t *w = (gps_user_data_t *)user_data;
362 GtkTable *box, *data_type_box;
364 w->proto_l = gtk_label_new (_("GPS Protocol:"));
365 w->proto_b = GTK_COMBO_BOX(gtk_combo_box_new_text ());
366 g_list_foreach (a_babel_device_list, append_element, w->proto_b);
368 // Maintain default to Garmin devices (assumed most popular/numerous device)
369 if ( last_active < 0 ) {
371 g_list_foreach (a_babel_device_list, find_garmin, NULL);
372 if ( garmin_entry < 0 )
373 // Not found - so set it to the first entry
377 last_active = garmin_entry;
380 gtk_combo_box_set_active (w->proto_b, last_active);
381 g_object_ref(w->proto_b);
383 w->ser_l = gtk_label_new (_("Serial Port:"));
384 w->ser_b = GTK_COMBO_BOX(gtk_combo_box_entry_new_text ());
386 gtk_combo_box_append_text (w->ser_b, "com1");
388 /* Here just try to see if the device is available which gets passed onto gpsbabel
389 List USB devices first as these will generally only be present if autogenerated by udev or similar
390 User is still able to set their own free text entry */
391 if (g_access ("/dev/ttyUSB0", R_OK) == 0)
392 gtk_combo_box_append_text (w->ser_b, "/dev/ttyUSB0");
393 if (g_access ("/dev/ttyUSB1", R_OK) == 0)
394 gtk_combo_box_append_text (w->ser_b, "/dev/ttyUSB1");
395 if (g_access ("/dev/ttyS0", R_OK) == 0)
396 gtk_combo_box_append_text (w->ser_b, "/dev/ttyS0");
397 if (g_access ("/dev/ttyS1", R_OK) == 0)
398 gtk_combo_box_append_text (w->ser_b, "/dev/ttyS1");
400 gtk_combo_box_append_text (w->ser_b, "usb:");
401 gtk_combo_box_set_active (w->ser_b, 0);
402 g_object_ref(w->ser_b);
404 w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
405 w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
407 w->get_tracks_l = gtk_label_new (_("Tracks:"));
408 w->get_tracks_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
409 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), last_get_tracks);
411 w->get_waypoints_l = gtk_label_new (_("Waypoints:"));
412 w->get_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
413 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), last_get_waypoints);
415 box = GTK_TABLE(gtk_table_new(2, 4, FALSE));
416 data_type_box = GTK_TABLE(gtk_table_new(4, 1, FALSE));
418 gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_l), 0, 1, 0, 1);
419 gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_b), 1, 2, 0, 1);
420 gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_l), 0, 1, 1, 2);
421 gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_b), 1, 2, 1, 2);
422 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_l), 0, 1, 0, 1);
423 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_b), 1, 2, 0, 1);
424 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_l), 2, 3, 0, 1);
425 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_b), 3, 4, 0, 1);
426 gtk_table_attach_defaults(box, GTK_WIDGET(data_type_box), 0, 2, 2, 3);
427 gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_l), 0, 1, 3, 4);
428 gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_b), 1, 3, 3, 4);
429 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(box), FALSE, FALSE, 5 );
431 gtk_widget_show_all ( dialog );
434 void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
436 GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel;
438 gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
440 gpslabel = gtk_label_new (_("GPS device: N/A"));
441 verlabel = gtk_label_new ("");
442 idlabel = gtk_label_new ("");
443 wplabel = gtk_label_new ("");
444 trklabel = gtk_label_new ("");
446 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), gpslabel, FALSE, FALSE, 5 );
447 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), wplabel, FALSE, FALSE, 5 );
448 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), trklabel, FALSE, FALSE, 5 );
450 gtk_widget_show_all ( dialog );
452 w_gps->gps_label = gpslabel;
453 w_gps->id_label = idlabel;
454 w_gps->ver_label = verlabel;
455 w_gps->progress_label = w_gps->wp_label = wplabel;
456 w_gps->trk_label = trklabel;
457 w_gps->total_count = -1;