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 static gboolean gps_acquire_in_progress = FALSE;
42 static gint last_active = -1;
43 static gboolean last_get_tracks = TRUE;
44 static gboolean last_get_waypoints = TRUE;
46 static gpointer datasource_gps_init_func ( );
47 static void datasource_gps_get_cmd_string ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
48 static void datasource_gps_cleanup ( gpointer user_data );
49 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
50 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
51 static void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data );
52 static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
54 VikDataSourceInterface vik_datasource_gps_interface = {
55 N_("Acquire from GPS"),
56 N_("Acquired from GPS"),
57 VIK_DATASOURCE_GPSBABEL_DIRECT,
58 VIK_DATASOURCE_CREATENEWLAYER,
59 VIK_DATASOURCE_INPUTTYPE_NONE,
62 (VikDataSourceInitFunc) datasource_gps_init_func,
63 (VikDataSourceCheckExistenceFunc) NULL,
64 (VikDataSourceAddSetupWidgetsFunc) datasource_gps_add_setup_widgets,
65 (VikDataSourceGetCmdStringFunc) datasource_gps_get_cmd_string,
66 (VikDataSourceProcessFunc) NULL,
67 (VikDataSourceProgressFunc) datasource_gps_progress,
68 (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
69 (VikDataSourceCleanupFunc) datasource_gps_cleanup,
70 (VikDataSourceOffFunc) datasource_gps_off
73 /*********************************************************
74 * Definitions and routines for acquiring data from GPS
75 *********************************************************/
77 /* widgets in setup dialog specific to GPS */
78 /* widgets in progress dialog specific to GPS */
79 /* also counts needed for progress */
86 GtkWidget *off_request_l;
87 GtkCheckButton *off_request_b;
88 GtkWidget *get_tracks_l;
89 GtkCheckButton *get_tracks_b;
90 GtkWidget *get_waypoints_l;
91 GtkCheckButton *get_waypoints_b;
99 GtkWidget *progress_label;
106 static gpointer datasource_gps_init_func ()
108 return g_malloc (sizeof(gps_user_data_t));
111 static void datasource_gps_get_cmd_string ( gpointer user_data, gchar **babelargs, gchar **input_file )
116 char *waypoints = NULL;
117 gps_user_data_t *w = (gps_user_data_t *)user_data;
119 if (gps_acquire_in_progress) {
120 *babelargs = *input_file = NULL;
123 gps_acquire_in_progress = TRUE;
125 last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
126 device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
128 last_get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
133 last_get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
134 if (last_get_waypoints)
139 *babelargs = g_strdup_printf("-D 9 %s %s -i %s", tracks, waypoints, device);
140 /* device points to static content => no free */
145 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
146 *input_file = g_strdup(ser);
148 g_debug(_("using cmdline '%s' and file '%s'\n"), *babelargs, *input_file);
152 static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **input_file )
156 gps_user_data_t *w = (gps_user_data_t *)user_data;
158 if (gps_acquire_in_progress) {
159 *babelargs = *input_file = NULL;
162 /* See if we should turn off the device */
163 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b))) {
167 last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
168 device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
169 if (!strcmp(device, "garmin")) {
170 device = "garmin,power_off";
172 else if (!strcmp(device, "navilink")) {
173 device = "navilink,power_off";
179 *babelargs = g_strdup_printf("-i %s", device);
180 /* device points to static content => no free */
183 ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
184 *input_file = g_strdup(ser);
188 static void datasource_gps_cleanup ( gpointer user_data )
190 g_free ( user_data );
191 gps_acquire_in_progress = FALSE;
194 static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
199 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
200 const gchar *tmp_str;
201 if (gps_data->progress_label == gps_data->wp_label)
202 tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt);
204 tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt);
205 s = g_strdup_printf(tmp_str, cnt);
206 gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
207 gtk_widget_show ( gps_data->progress_label );
208 gps_data->total_count = cnt;
214 static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
219 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
221 if (cnt < gps_data->total_count) {
222 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");
224 s = g_strdup_printf(_("Downloaded %d %s."), cnt, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
226 gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
232 static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
237 s = g_strdup_printf(_("GPS Device: %s"), info);
238 gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
245 * This routine relies on gpsbabel's diagnostic output to display the progress information.
246 * These outputs differ when different GPS devices are used, so we will need to test
247 * them on several and add the corresponding support.
249 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
252 gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
255 case BABEL_DIAG_OUTPUT:
256 line = (gchar *)data;
258 /* tells us how many items there will be */
259 if (strstr(line, "Xfer Wpt")) {
260 gps_data->progress_label = gps_data->wp_label;
262 if (strstr(line, "Xfer Trk")) {
263 gps_data->progress_label = gps_data->trk_label;
265 if (strstr(line, "PRDDAT")) {
266 gchar **tokens = g_strsplit(line, " ", 0);
272 while (tokens[n_tokens])
276 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
278 sscanf(tokens[i], "%x", &ch);
282 set_gps_info(info, w);
286 /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
287 if (strstr(line, "Unit:")) {
288 gchar **tokens = g_strsplit(line, "\t", 0);
290 while (tokens[n_tokens])
294 set_gps_info(tokens[1], w);
298 if (strstr(line, "RECORD")) {
301 if (strlen(line) > 20) {
302 sscanf(line+17, "%x", &lsb);
303 sscanf(line+20, "%x", &msb);
304 cnt = lsb + msb * 256;
305 set_total_count(cnt, w);
309 if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
311 set_current_count(gps_data->count, w);
321 void append_element (gpointer elem, gpointer user_data)
323 GtkComboBox *combo = GTK_COMBO_BOX (user_data);
324 const gchar *text = ((BabelDevice*)elem)->label;
325 gtk_combo_box_append_text (combo, text);
328 static gint find_entry = -1;
329 static gint garmin_entry = -1;
331 static void find_garmin (gpointer elem, gpointer user_data)
333 const gchar *name = ((BabelDevice*)elem)->name;
335 if (!strcmp(name, "garmin")) {
336 garmin_entry = find_entry;
340 void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
342 gps_user_data_t *w = (gps_user_data_t *)user_data;
343 GtkTable *box, *data_type_box;
345 w->proto_l = gtk_label_new (_("GPS Protocol:"));
346 w->proto_b = GTK_COMBO_BOX(gtk_combo_box_new_text ());
347 g_list_foreach (a_babel_device_list, append_element, w->proto_b);
349 // Maintain default to Garmin devices (assumed most popular/numerous device)
350 if ( last_active < 0 ) {
352 g_list_foreach (a_babel_device_list, find_garmin, NULL);
353 if ( garmin_entry < 0 )
354 // Not found - so set it to the first entry
358 last_active = garmin_entry;
361 gtk_combo_box_set_active (w->proto_b, last_active);
362 g_object_ref(w->proto_b);
364 w->ser_l = gtk_label_new (_("Serial Port:"));
365 w->ser_b = GTK_COMBO_BOX(gtk_combo_box_entry_new_text ());
367 gtk_combo_box_append_text (w->ser_b, "com1");
369 /* Here just try to see if the device is available which gets passed onto gpsbabel
370 List USB devices first as these will generally only be present if autogenerated by udev or similar
371 User is still able to set their own free text entry */
372 if (g_access ("/dev/ttyUSB0", R_OK) == 0)
373 gtk_combo_box_append_text (w->ser_b, "/dev/ttyUSB0");
374 if (g_access ("/dev/ttyUSB1", R_OK) == 0)
375 gtk_combo_box_append_text (w->ser_b, "/dev/ttyUSB1");
376 if (g_access ("/dev/ttyS0", R_OK) == 0)
377 gtk_combo_box_append_text (w->ser_b, "/dev/ttyS0");
378 if (g_access ("/dev/ttyS1", R_OK) == 0)
379 gtk_combo_box_append_text (w->ser_b, "/dev/ttyS1");
381 gtk_combo_box_append_text (w->ser_b, "usb:");
382 gtk_combo_box_set_active (w->ser_b, 0);
383 g_object_ref(w->ser_b);
385 w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
386 w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
388 w->get_tracks_l = gtk_label_new (_("Tracks:"));
389 w->get_tracks_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
390 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), last_get_tracks);
392 w->get_waypoints_l = gtk_label_new (_("Waypoints:"));
393 w->get_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
394 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), last_get_waypoints);
396 box = GTK_TABLE(gtk_table_new(2, 4, FALSE));
397 data_type_box = GTK_TABLE(gtk_table_new(4, 1, FALSE));
399 gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_l), 0, 1, 0, 1);
400 gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_b), 1, 2, 0, 1);
401 gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_l), 0, 1, 1, 2);
402 gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_b), 1, 2, 1, 2);
403 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_l), 0, 1, 0, 1);
404 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_b), 1, 2, 0, 1);
405 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_l), 2, 3, 0, 1);
406 gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_b), 3, 4, 0, 1);
407 gtk_table_attach_defaults(box, GTK_WIDGET(data_type_box), 0, 2, 2, 3);
408 gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_l), 0, 1, 3, 4);
409 gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_b), 1, 3, 3, 4);
410 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(box), FALSE, FALSE, 5 );
412 gtk_widget_show_all ( dialog );
415 void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
417 GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel;
419 gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
421 gpslabel = gtk_label_new (_("GPS device: N/A"));
422 verlabel = gtk_label_new ("");
423 idlabel = gtk_label_new ("");
424 wplabel = gtk_label_new ("");
425 trklabel = gtk_label_new ("");
427 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), gpslabel, FALSE, FALSE, 5 );
428 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), wplabel, FALSE, FALSE, 5 );
429 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), trklabel, FALSE, FALSE, 5 );
431 gtk_widget_show_all ( dialog );
433 w_gps->gps_label = gpslabel;
434 w_gps->id_label = idlabel;
435 w_gps->ver_label = verlabel;
436 w_gps->progress_label = w_gps->wp_label = wplabel;
437 w_gps->trk_label = trklabel;
438 w_gps->total_count = -1;