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