]> git.street.me.uk Git - andy/viking.git/blame - src/vikgpslayer.c
Enable using an optional file cache for Mapnik Renderings.
[andy/viking.git] / src / vikgpslayer.c
CommitLineData
b364d6bc
QT
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-2008, Quy Tonthat <qtonthat@gmail.com>
b364d6bc
QT
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
58a642b6
GB
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
b87d3952 27#include <stdlib.h>
8c00358d 28#ifdef HAVE_MATH_H
b87d3952 29#include <math.h>
8c00358d 30#endif
b364d6bc 31#include "viking.h"
5bfafde9 32#include "icons/icons.h"
b364d6bc
QT
33#include "babel.h"
34
99163c34
RN
35#ifdef HAVE_UNISTD_H
36#include <unistd.h>
37#endif
8c00358d 38#ifdef HAVE_STRING_H
b364d6bc 39#include <string.h>
8c00358d 40#endif
99163c34 41#include <glib/gstdio.h>
b364d6bc 42#include <glib/gprintf.h>
4c77d5e0 43#include <glib/gi18n.h>
001a86db 44#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952 45#include <gps.h>
8b5838b2 46#include "vikutils.h"
58a642b6 47#endif
b364d6bc 48
fdca5edb
QT
49static VikGpsLayer *vik_gps_layer_create (VikViewport *vp);
50static void vik_gps_layer_realize ( VikGpsLayer *val, VikTreeview *vt, GtkTreeIter *layer_iter );
51static void vik_gps_layer_free ( VikGpsLayer *val );
45c5ac8e 52static void vik_gps_layer_draw ( VikGpsLayer *val, VikViewport *vp );
30a9c13f 53static VikGpsLayer *vik_gps_layer_new ( VikViewport *vp );
b364d6bc 54
b364d6bc
QT
55static void gps_layer_marshall( VikGpsLayer *val, guint8 **data, gint *len );
56static VikGpsLayer *gps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
57static gboolean gps_layer_set_param ( VikGpsLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
58static VikLayerParamData gps_layer_get_param ( VikGpsLayer *vgl, guint16 id, gboolean is_file_operation );
b364d6bc 59
45da1f2f
RN
60static const gchar* gps_layer_tooltip ( VikGpsLayer *vgl );
61
b364d6bc
QT
62static void gps_layer_change_coord_mode ( VikGpsLayer *val, VikCoordMode mode );
63static void gps_layer_add_menu_items( VikGpsLayer *vtl, GtkMenu *menu, gpointer vlp );
b364d6bc 64
b364d6bc
QT
65static void gps_upload_cb( gpointer layer_and_vlp[2] );
66static void gps_download_cb( gpointer layer_and_vlp[2] );
700b0908
QT
67static void gps_empty_upload_cb( gpointer layer_and_vlp[2] );
68static void gps_empty_download_cb( gpointer layer_and_vlp[2] );
69static void gps_empty_all_cb( gpointer layer_and_vlp[2] );
728db5b5 70#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
22d1e285 71static void gps_empty_realtime_cb( gpointer layer_and_vlp[2] );
b87d3952 72static void gps_start_stop_tracking_cb( gpointer layer_and_vlp[2] );
001a86db 73static void realtime_tracking_draw(VikGpsLayer *vgl, VikViewport *vp);
e92cb4e5
RN
74static void rt_gpsd_disconnect(VikGpsLayer *vgl);
75static gboolean rt_gpsd_connect(VikGpsLayer *vgl, gboolean ask_if_failed);
58a642b6 76#endif
b364d6bc 77
5f955595
RN
78// Shouldn't need to use these much any more as the protocol is now saved as a string.
79// They are kept for compatibility loading old .vik files
80typedef enum {GARMIN_P = 0, MAGELLAN_P, DELORME_P, NAVILINK_P, OLD_NUM_PROTOCOLS} vik_gps_proto;
81static gchar * protocols_args[] = {"garmin", "magellan", "delbin", "navilink", NULL};
8d70f073
MA
82#ifdef WINDOWS
83static gchar * params_ports[] = {"com1", "usb:", NULL};
84#else
7963d365 85static gchar * params_ports[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyUSB0", "/dev/ttyUSB1", "usb:", NULL};
8d70f073 86#endif
99163c34
RN
87/* NUM_PORTS not actually used */
88/* #define NUM_PORTS (sizeof(params_ports)/sizeof(params_ports[0]) - 1) */
bb8aed99
GB
89/* Compatibility with previous versions */
90#ifdef WINDOWS
91static gchar * old_params_ports[] = {"com1", "usb:", NULL};
92#else
93static gchar * old_params_ports[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyUSB0", "/dev/ttyUSB1", "usb:", NULL};
94#endif
95#define OLD_NUM_PORTS (sizeof(old_params_ports)/sizeof(old_params_ports[0]) - 1)
b364d6bc
QT
96
97typedef struct {
98 GMutex *mutex;
e4b02b41 99 vik_gps_dir direction;
b364d6bc
QT
100 gchar *port;
101 gboolean ok;
102 gint total_count;
103 gint count;
104 VikTrwLayer *vtl;
778f41c5 105 VikTrack *track;
b364d6bc 106 gchar *cmd_args;
e4b02b41 107 gchar *window_title;
b364d6bc
QT
108 GtkWidget *dialog;
109 GtkWidget *status_label;
110 GtkWidget *gps_label;
111 GtkWidget *ver_label;
112 GtkWidget *id_label;
113 GtkWidget *wp_label;
b364d6bc 114 GtkWidget *trk_label;
0d2b891f
RN
115 GtkWidget *rte_label;
116 GtkWidget *progress_label;
117 vik_gps_xfer_type progress_type;
b870a512 118 VikViewport *vvp;
728db5b5 119#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b870a512
RN
120 gboolean realtime_tracking;
121#endif
b364d6bc
QT
122} GpsSession;
123static void gps_session_delete(GpsSession *sess);
124
58a642b6 125static gchar *params_groups[] = {
267c99de 126 N_("Data Mode"),
728db5b5 127#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
267c99de 128 N_("Realtime Tracking Mode"),
58a642b6
GB
129#endif
130};
131
b87d3952
QT
132enum {GROUP_DATA_MODE, GROUP_REALTIME_MODE};
133
a7023a1b
RN
134
135static VikLayerParamData gps_protocol_default ( void )
136{
137 VikLayerParamData data;
138 data.s = g_strdup ( "garmin" );
139 return data;
140}
141
142static VikLayerParamData gps_port_default ( void )
143{
144 VikLayerParamData data;
145 data.s = g_strdup ( "usb:" );
146#ifndef WINDOWS
147 /* Attempt to auto set default USB serial port entry */
148 /* Ordered to make lowest device favourite if available */
149 if (g_access ("/dev/ttyUSB1", R_OK) == 0) {
150 if ( data.s )
151 g_free ( (gchar *)data.s );
152 data.s = g_strdup ("/dev/ttyUSB1");
153 }
154 if (g_access ("/dev/ttyUSB0", R_OK) == 0) {
155 if ( data.s )
156 g_free ( (gchar *)data.s );
157 data.s = g_strdup ("/dev/ttyUSB0");
158 }
159#endif
160 return data;
161}
162
728db5b5 163#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
dc3a1898 164static gchar *params_vehicle_position[] = {
267c99de
RN
165 N_("Keep vehicle at center"),
166 N_("Keep vehicle on screen"),
167 N_("Disable"),
dc3a1898
QT
168 NULL
169};
170enum {
171 VEHICLE_POSITION_CENTERED = 0,
172 VEHICLE_POSITION_ON_SCREEN,
173 VEHICLE_POSITION_NONE,
174};
a7023a1b
RN
175
176static VikLayerParamData moving_map_method_default ( void ) { return VIK_LPD_UINT ( VEHICLE_POSITION_ON_SCREEN ); }
177
178static VikLayerParamData gpsd_host_default ( void )
179{
180 VikLayerParamData data;
181 data.s = g_strdup ( "localhost" );
182 return data;
183}
184
185static VikLayerParamData gpsd_port_default ( void )
186{
187 VikLayerParamData data;
188 data.s = g_strdup ( DEFAULT_GPSD_PORT );
189 return data;
190}
191
192static VikLayerParamData gpsd_retry_interval_default ( void )
193{
194 VikLayerParamData data;
195 data.s = g_strdup ( "10" );
196 return data;
197}
198
dc3a1898
QT
199#endif
200
b364d6bc 201static VikLayerParam gps_layer_params[] = {
a7023a1b
RN
202 // NB gps_layer_inst_init() is performed after parameter registeration
203 // thus to give the protocols some potential values use the old static list
204 // TODO: find another way to use gps_layer_inst_init()?
a87f8fa1
RN
205 { VIK_LAYER_GPS, "gps_protocol", VIK_LAYER_PARAM_STRING, GROUP_DATA_MODE, N_("GPS Protocol:"), VIK_LAYER_WIDGET_COMBOBOX, protocols_args, NULL, NULL, gps_protocol_default, NULL, NULL }, // List reassigned at runtime
206 { VIK_LAYER_GPS, "gps_port", VIK_LAYER_PARAM_STRING, GROUP_DATA_MODE, N_("Serial Port:"), VIK_LAYER_WIDGET_COMBOBOX, params_ports, NULL, NULL, gps_port_default, NULL, NULL },
207 { VIK_LAYER_GPS, "gps_download_tracks", VIK_LAYER_PARAM_BOOLEAN, GROUP_DATA_MODE, N_("Download Tracks:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
208 { VIK_LAYER_GPS, "gps_upload_tracks", VIK_LAYER_PARAM_BOOLEAN, GROUP_DATA_MODE, N_("Upload Tracks:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
209 { VIK_LAYER_GPS, "gps_download_routes", VIK_LAYER_PARAM_BOOLEAN, GROUP_DATA_MODE, N_("Download Routes:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
210 { VIK_LAYER_GPS, "gps_upload_routes", VIK_LAYER_PARAM_BOOLEAN, GROUP_DATA_MODE, N_("Upload Routes:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
211 { VIK_LAYER_GPS, "gps_download_waypoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_DATA_MODE, N_("Download Waypoints:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
212 { VIK_LAYER_GPS, "gps_upload_waypoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_DATA_MODE, N_("Upload Waypoints:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
728db5b5 213#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
a87f8fa1
RN
214 { VIK_LAYER_GPS, "record_tracking", VIK_LAYER_PARAM_BOOLEAN, GROUP_REALTIME_MODE, N_("Recording tracks"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
215 { VIK_LAYER_GPS, "center_start_tracking", VIK_LAYER_PARAM_BOOLEAN, GROUP_REALTIME_MODE, N_("Jump to current position on start"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
216 { VIK_LAYER_GPS, "moving_map_method", VIK_LAYER_PARAM_UINT, GROUP_REALTIME_MODE, N_("Moving Map Method:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_vehicle_position, NULL, NULL, moving_map_method_default, NULL, NULL },
8b5838b2 217 { VIK_LAYER_GPS, "realtime_update_statusbar", VIK_LAYER_PARAM_BOOLEAN, GROUP_REALTIME_MODE, N_("Update Statusbar:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, N_("Display information in the statusbar on GPS updates"), vik_lpd_true_default, NULL, NULL },
a87f8fa1
RN
218 { VIK_LAYER_GPS, "gpsd_host", VIK_LAYER_PARAM_STRING, GROUP_REALTIME_MODE, N_("Gpsd Host:"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, gpsd_host_default, NULL, NULL },
219 { VIK_LAYER_GPS, "gpsd_port", VIK_LAYER_PARAM_STRING, GROUP_REALTIME_MODE, N_("Gpsd Port:"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, gpsd_port_default, NULL, NULL },
220 { VIK_LAYER_GPS, "gpsd_retry_interval", VIK_LAYER_PARAM_STRING, GROUP_REALTIME_MODE, N_("Gpsd Retry Interval (seconds):"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, gpsd_retry_interval_default, NULL, NULL },
001a86db 221#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc 222};
58a642b6
GB
223enum {
224 PARAM_PROTOCOL=0, PARAM_PORT,
d6c58ab9 225 PARAM_DOWNLOAD_TRACKS, PARAM_UPLOAD_TRACKS,
0d2b891f 226 PARAM_DOWNLOAD_ROUTES, PARAM_UPLOAD_ROUTES,
d6c58ab9 227 PARAM_DOWNLOAD_WAYPOINTS, PARAM_UPLOAD_WAYPOINTS,
728db5b5 228#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
8b5838b2
RN
229 PARAM_REALTIME_REC,
230 PARAM_REALTIME_CENTER_START,
231 PARAM_VEHICLE_POSITION,
232 PARAM_REALTIME_UPDATE_STATUSBAR,
233 PARAM_GPSD_HOST,
234 PARAM_GPSD_PORT,
235 PARAM_GPSD_RETRY_INTERVAL,
001a86db 236#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
58a642b6 237 NUM_PARAMS};
b364d6bc
QT
238
239VikLayerInterface vik_gps_layer_interface = {
db386630 240 "GPS",
affcc0f2 241 N_("GPS"),
75078768 242 NULL,
5bfafde9 243 &vikgpslayer_pixbuf,
b364d6bc
QT
244
245 NULL,
246 0,
247
248 gps_layer_params,
249 NUM_PARAMS,
b87d3952
QT
250 params_groups,
251 sizeof(params_groups)/sizeof(params_groups[0]),
b364d6bc 252
81ee8fa7 253 VIK_MENU_ITEM_ALL,
5a4a28bf 254
b364d6bc
QT
255 (VikLayerFuncCreate) vik_gps_layer_create,
256 (VikLayerFuncRealize) vik_gps_layer_realize,
257 (VikLayerFuncPostRead) NULL,
258 (VikLayerFuncFree) vik_gps_layer_free,
259
260 (VikLayerFuncProperties) NULL,
261 (VikLayerFuncDraw) vik_gps_layer_draw,
262 (VikLayerFuncChangeCoordMode) gps_layer_change_coord_mode,
263
20c7a3a0
QT
264 (VikLayerFuncSetMenuItemsSelection) NULL,
265 (VikLayerFuncGetMenuItemsSelection) NULL,
266
b364d6bc
QT
267 (VikLayerFuncAddMenuItems) gps_layer_add_menu_items,
268 (VikLayerFuncSublayerAddMenuItems) NULL,
269
270 (VikLayerFuncSublayerRenameRequest) NULL,
271 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 272 (VikLayerFuncSublayerTooltip) NULL,
45da1f2f 273 (VikLayerFuncLayerTooltip) gps_layer_tooltip,
a5dcfdb7 274 (VikLayerFuncLayerSelected) NULL,
b364d6bc 275
b364d6bc
QT
276 (VikLayerFuncMarshall) gps_layer_marshall,
277 (VikLayerFuncUnmarshall) gps_layer_unmarshall,
278
279 (VikLayerFuncSetParam) gps_layer_set_param,
280 (VikLayerFuncGetParam) gps_layer_get_param,
db43cfa4 281 (VikLayerFuncChangeParam) NULL,
b364d6bc
QT
282
283 (VikLayerFuncReadFileData) NULL,
284 (VikLayerFuncWriteFileData) NULL,
285
286 (VikLayerFuncDeleteItem) NULL,
d5874ef9 287 (VikLayerFuncCutItem) NULL,
b364d6bc
QT
288 (VikLayerFuncCopyItem) NULL,
289 (VikLayerFuncPasteItem) NULL,
290 (VikLayerFuncFreeCopiedItem) NULL,
b7b6b047 291 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
292
293 (VikLayerFuncSelectClick) NULL,
08f14055
RN
294 (VikLayerFuncSelectMove) NULL,
295 (VikLayerFuncSelectRelease) NULL,
e46f259a 296 (VikLayerFuncSelectedViewportMenu) NULL,
b364d6bc
QT
297};
298
58a642b6 299enum {TRW_DOWNLOAD=0, TRW_UPLOAD,
728db5b5 300#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
58a642b6
GB
301 TRW_REALTIME,
302#endif
303 NUM_TRW};
304static gchar * trw_names[] = {
4c77d5e0 305 N_("GPS Download"), N_("GPS Upload"),
728db5b5 306#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
4c77d5e0 307 N_("GPS Realtime Tracking"),
58a642b6
GB
308#endif
309};
b87d3952 310
728db5b5 311#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b87d3952
QT
312typedef struct {
313 struct gps_data_t gpsd;
314 VikGpsLayer *vgl;
315} VglGpsd;
316
317typedef struct {
c4e61875 318 struct gps_fix_t fix;
a2817d3c 319 gint satellites_used;
b87d3952
QT
320 gboolean dirty; /* needs to be saved */
321} GpsFix;
001a86db 322#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b87d3952 323
b364d6bc
QT
324struct _VikGpsLayer {
325 VikLayer vl;
326 VikTrwLayer * trw_children[NUM_TRW];
f253a6a6
QT
327 GList * children; /* used only for writing file */
328 int cur_read_child; /* used only for reading file */
728db5b5 329#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b87d3952 330 VglGpsd *vgpsd;
ae198aa3 331 gboolean realtime_tracking; /* set/reset only by the callback */
c5bc70c3 332 gboolean first_realtime_trackpoint;
b87d3952
QT
333 GpsFix realtime_fix;
334 GpsFix last_fix;
335
b87d3952 336 VikTrack *realtime_track;
b87d3952
QT
337
338 GIOChannel *realtime_io_channel;
339 guint realtime_io_watch_id;
c5bc70c3 340 guint realtime_retry_timer;
b87d3952
QT
341 GdkGC *realtime_track_gc;
342 GdkGC *realtime_track_bg_gc;
343 GdkGC *realtime_track_pt_gc;
344 GdkGC *realtime_track_pt1_gc;
345 GdkGC *realtime_track_pt2_gc;
346
b364d6bc 347 /* params */
b87d3952
QT
348 gchar *gpsd_host;
349 gchar *gpsd_port;
c5bc70c3 350 gint gpsd_retry_interval;
b87d3952
QT
351 gboolean realtime_record;
352 gboolean realtime_jump_to_start;
dc3a1898 353 guint vehicle_position;
8b5838b2
RN
354 gboolean realtime_update_statusbar;
355 VikTrackpoint *trkpt;
356 VikTrackpoint *trkpt_prev;
001a86db 357#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
5f955595 358 gchar *protocol;
ce37ab9b 359 gchar *serial_port;
d6c58ab9 360 gboolean download_tracks;
0d2b891f 361 gboolean download_routes;
d6c58ab9
RN
362 gboolean download_waypoints;
363 gboolean upload_tracks;
0d2b891f 364 gboolean upload_routes;
d6c58ab9 365 gboolean upload_waypoints;
b364d6bc
QT
366};
367
5f955595
RN
368/**
369 * Overwrite the static setup with dynamically generated GPS Babel device list
370 */
371static void gps_layer_inst_init ( VikGpsLayer *self )
372{
373 gint new_proto = 0;
374 // +1 for luck (i.e the NULL terminator)
375 gchar **new_protocols = g_malloc(1 + g_list_length(a_babel_device_list)*sizeof(gpointer));
376
377 GList *gl = g_list_first ( a_babel_device_list );
378 while ( gl ) {
379 // should be using label property but use name for now
380 // thus don't need to mess around converting label to name later on
381 new_protocols[new_proto++] = ((BabelDevice*)gl->data)->name;
382 gl = g_list_next ( gl );
383 }
384 new_protocols[new_proto] = NULL;
385
a7023a1b 386 vik_gps_layer_interface.params[PARAM_PROTOCOL].widget_data = new_protocols;
5f955595
RN
387}
388
b364d6bc
QT
389GType vik_gps_layer_get_type ()
390{
391 static GType val_type = 0;
392
393 if (!val_type)
394 {
395 static const GTypeInfo val_info =
396 {
397 sizeof (VikGpsLayerClass),
398 NULL, /* base_init */
399 NULL, /* base_finalize */
400 NULL, /* class init */
401 NULL, /* class_finalize */
402 NULL, /* class_data */
403 sizeof (VikGpsLayer),
404 0,
5f955595 405 (GInstanceInitFunc) gps_layer_inst_init,
b364d6bc
QT
406 };
407 val_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGpsLayer", &val_info, 0 );
408 }
409
410 return val_type;
411}
412
fdca5edb 413static VikGpsLayer *vik_gps_layer_create (VikViewport *vp)
b364d6bc 414{
c4e61875
QT
415 int i;
416
b87d3952 417 VikGpsLayer *rv = vik_gps_layer_new (vp);
b364d6bc 418 vik_layer_rename ( VIK_LAYER(rv), vik_gps_layer_interface.name );
c4e61875
QT
419
420 for (i = 0; i < NUM_TRW; i++) {
0ab35525 421 rv->trw_children[i] = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vp, FALSE ));
c4e61875
QT
422 vik_layer_set_menu_items_selection(VIK_LAYER(rv->trw_children[i]), VIK_MENU_ITEM_ALL & ~(VIK_MENU_ITEM_CUT|VIK_MENU_ITEM_DELETE));
423 }
b364d6bc
QT
424 return rv;
425}
426
45da1f2f
RN
427static const gchar* gps_layer_tooltip ( VikGpsLayer *vgl )
428{
5f955595 429 return vgl->protocol;
45da1f2f
RN
430}
431
b364d6bc
QT
432/* "Copy" */
433static void gps_layer_marshall( VikGpsLayer *vgl, guint8 **data, gint *datalen )
434{
435 VikLayer *child_layer;
436 guint8 *ld;
437 gint ll;
438 GByteArray* b = g_byte_array_new ();
439 gint len;
440 gint i;
441
442#define alm_append(obj, sz) \
443 len = (sz); \
444 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
445 g_byte_array_append ( b, (guint8 *)(obj), len );
446
447 vik_layer_marshall_params(VIK_LAYER(vgl), &ld, &ll);
448 alm_append(ld, ll);
449 g_free(ld);
450
451 for (i = 0; i < NUM_TRW; i++) {
452 child_layer = VIK_LAYER(vgl->trw_children[i]);
453 vik_layer_marshall(child_layer, &ld, &ll);
454 if (ld) {
455 alm_append(ld, ll);
456 g_free(ld);
457 }
458 }
459 *data = b->data;
460 *datalen = b->len;
461 g_byte_array_free(b, FALSE);
462#undef alm_append
463}
464
465/* "Paste" */
466static VikGpsLayer *gps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
467{
468#define alm_size (*(gint *)data)
469#define alm_next \
470 len -= sizeof(gint) + alm_size; \
471 data += sizeof(gint) + alm_size;
472
30a9c13f 473 VikGpsLayer *rv = vik_gps_layer_new(vvp);
b364d6bc
QT
474 VikLayer *child_layer;
475 gint i;
476
477 vik_layer_unmarshall_params ( VIK_LAYER(rv), data+sizeof(gint), alm_size, vvp );
478 alm_next;
479
480 i = 0;
481 while (len>0 && i < NUM_TRW) {
482 child_layer = vik_layer_unmarshall ( data + sizeof(gint), alm_size, vvp );
483 if (child_layer) {
fdca5edb 484 rv->trw_children[i++] = (VikTrwLayer *)child_layer;
325af20b
RN
485 // NB no need to attach signal update handler here
486 // as this will always be performed later on in vik_gps_layer_realize()
b364d6bc
QT
487 }
488 alm_next;
489 }
490 // g_print("gps_layer_unmarshall ended with len=%d\n", len);
491 g_assert(len == 0);
492 return rv;
493#undef alm_size
494#undef alm_next
495}
496
158b3642 497static gboolean gps_layer_set_param ( VikGpsLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
b364d6bc
QT
498{
499 switch ( id )
500 {
501 case PARAM_PROTOCOL:
5f955595
RN
502 if (data.s) {
503 g_free(vgl->protocol);
504 // Backwards Compatibility: previous versions <v1.4 stored protocol as an array index
505 int index = data.s[0] - '0';
506 if (data.s[0] != '\0' &&
507 g_ascii_isdigit (data.s[0]) &&
508 data.s[1] == '\0' &&
509 index < OLD_NUM_PROTOCOLS)
510 // It is a single digit: activate compatibility
511 vgl->protocol = g_strdup(protocols_args[index]);
512 else
513 vgl->protocol = g_strdup(data.s);
514 g_debug("%s: %s", __FUNCTION__, vgl->protocol);
515 }
b364d6bc 516 else
4c77d5e0 517 g_warning(_("Unknown GPS Protocol"));
b364d6bc
QT
518 break;
519 case PARAM_PORT:
5f955595 520 if (data.s) {
ce37ab9b 521 g_free(vgl->serial_port);
5f955595 522 // Backwards Compatibility: previous versions <v0.9.91 stored serial_port as an array index
bb8aed99
GB
523 int index = data.s[0] - '0';
524 if (data.s[0] != '\0' &&
525 g_ascii_isdigit (data.s[0]) &&
526 data.s[1] == '\0' &&
527 index < OLD_NUM_PORTS)
528 /* It is a single digit: activate compatibility */
529 vgl->serial_port = g_strdup(old_params_ports[index]);
530 else
531 vgl->serial_port = g_strdup(data.s);
5f955595
RN
532 g_debug("%s: %s", __FUNCTION__, vgl->serial_port);
533 }
b364d6bc 534 else
4c77d5e0 535 g_warning(_("Unknown serial port device"));
b364d6bc 536 break;
d6c58ab9
RN
537 case PARAM_DOWNLOAD_TRACKS:
538 vgl->download_tracks = data.b;
539 break;
540 case PARAM_UPLOAD_TRACKS:
541 vgl->upload_tracks = data.b;
542 break;
0d2b891f
RN
543 case PARAM_DOWNLOAD_ROUTES:
544 vgl->download_routes = data.b;
545 break;
546 case PARAM_UPLOAD_ROUTES:
547 vgl->upload_routes = data.b;
548 break;
d6c58ab9
RN
549 case PARAM_DOWNLOAD_WAYPOINTS:
550 vgl->download_waypoints = data.b;
551 break;
552 case PARAM_UPLOAD_WAYPOINTS:
553 vgl->upload_waypoints = data.b;
554 break;
728db5b5 555#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b87d3952 556 case PARAM_GPSD_HOST:
a7023a1b
RN
557 if (data.s) {
558 if (vgl->gpsd_host)
559 g_free(vgl->gpsd_host);
560 vgl->gpsd_host = g_strdup(data.s);
561 }
b87d3952
QT
562 break;
563 case PARAM_GPSD_PORT:
a7023a1b 564 if (data.s) {
fe6ce054
RN
565 if (vgl->gpsd_port)
566 g_free(vgl->gpsd_port);
a7023a1b
RN
567 vgl->gpsd_port = g_strdup(data.s);
568 }
b87d3952 569 break;
c5bc70c3
QT
570 case PARAM_GPSD_RETRY_INTERVAL:
571 vgl->gpsd_retry_interval = strtol(data.s, NULL, 10);
572 break;
b87d3952
QT
573 case PARAM_REALTIME_REC:
574 vgl->realtime_record = data.b;
575 break;
576 case PARAM_REALTIME_CENTER_START:
577 vgl->realtime_jump_to_start = data.b;
578 break;
dc3a1898
QT
579 case PARAM_VEHICLE_POSITION:
580 vgl->vehicle_position = data.u;
b87d3952 581 break;
8b5838b2
RN
582 case PARAM_REALTIME_UPDATE_STATUSBAR:
583 vgl->realtime_update_statusbar = data.b;
584 break;
001a86db 585#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b87d3952
QT
586 default:
587 g_warning("gps_layer_set_param(): unknown parameter");
b364d6bc
QT
588 }
589
590 return TRUE;
591}
592
158b3642 593static VikLayerParamData gps_layer_get_param ( VikGpsLayer *vgl, guint16 id, gboolean is_file_operation )
b364d6bc
QT
594{
595 VikLayerParamData rv;
596 switch ( id )
597 {
598 case PARAM_PROTOCOL:
5f955595
RN
599 rv.s = vgl->protocol;
600 g_debug("%s: %s", __FUNCTION__, rv.s);
b364d6bc
QT
601 break;
602 case PARAM_PORT:
ce37ab9b
GB
603 rv.s = vgl->serial_port;
604 g_debug("%s: %s", __FUNCTION__, rv.s);
b364d6bc 605 break;
d6c58ab9
RN
606 case PARAM_DOWNLOAD_TRACKS:
607 rv.b = vgl->download_tracks;
608 break;
609 case PARAM_UPLOAD_TRACKS:
610 rv.b = vgl->upload_tracks;
611 break;
0d2b891f
RN
612 case PARAM_DOWNLOAD_ROUTES:
613 rv.b = vgl->download_routes;
614 break;
615 case PARAM_UPLOAD_ROUTES:
616 rv.b = vgl->upload_routes;
617 break;
d6c58ab9
RN
618 case PARAM_DOWNLOAD_WAYPOINTS:
619 rv.b = vgl->download_waypoints;
620 break;
621 case PARAM_UPLOAD_WAYPOINTS:
622 rv.b = vgl->upload_waypoints;
623 break;
728db5b5 624#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b87d3952
QT
625 case PARAM_GPSD_HOST:
626 rv.s = vgl->gpsd_host ? vgl->gpsd_host : "";
627 break;
628 case PARAM_GPSD_PORT:
629 rv.s = vgl->gpsd_port ? vgl->gpsd_port : g_strdup(DEFAULT_GPSD_PORT);
630 break;
c5bc70c3
QT
631 case PARAM_GPSD_RETRY_INTERVAL:
632 rv.s = g_strdup_printf("%d", vgl->gpsd_retry_interval);
633 break;
b87d3952
QT
634 case PARAM_REALTIME_REC:
635 rv.b = vgl->realtime_record;
636 break;
637 case PARAM_REALTIME_CENTER_START:
638 rv.b = vgl->realtime_jump_to_start;
639 break;
dc3a1898
QT
640 case PARAM_VEHICLE_POSITION:
641 rv.u = vgl->vehicle_position;
b87d3952 642 break;
8b5838b2
RN
643 case PARAM_REALTIME_UPDATE_STATUSBAR:
644 rv.u = vgl->realtime_update_statusbar;
645 break;
001a86db 646#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc 647 default:
4c77d5e0 648 g_warning(_("%s: unknown parameter"), __FUNCTION__);
b364d6bc
QT
649 }
650
b364d6bc
QT
651 return rv;
652}
653
b87d3952 654VikGpsLayer *vik_gps_layer_new (VikViewport *vp)
b364d6bc
QT
655{
656 gint i;
657 VikGpsLayer *vgl = VIK_GPS_LAYER ( g_object_new ( VIK_GPS_LAYER_TYPE, NULL ) );
a0c65899 658 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GPS );
b364d6bc
QT
659 for (i = 0; i < NUM_TRW; i++) {
660 vgl->trw_children[i] = NULL;
661 }
7886de28 662 vgl->children = NULL;
f253a6a6 663 vgl->cur_read_child = 0;
b364d6bc 664
728db5b5 665#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
c5bc70c3 666 vgl->first_realtime_trackpoint = FALSE;
8b5838b2
RN
667 vgl->trkpt = NULL;
668 vgl->trkpt_prev = NULL;
b87d3952 669 vgl->vgpsd = NULL;
c5bc70c3
QT
670 vgl->realtime_io_channel = NULL;
671 vgl->realtime_io_watch_id = 0;
672 vgl->realtime_retry_timer = 0;
8aff54f2
RN
673 if ( vp ) {
674 vgl->realtime_track_gc = vik_viewport_new_gc ( vp, "#203070", 2 );
675 vgl->realtime_track_bg_gc = vik_viewport_new_gc ( vp, "grey", 2 );
676 vgl->realtime_track_pt1_gc = vik_viewport_new_gc ( vp, "red", 2 );
677 vgl->realtime_track_pt2_gc = vik_viewport_new_gc ( vp, "green", 2 );
678 vgl->realtime_track_pt_gc = vgl->realtime_track_pt1_gc;
679 }
b87d3952 680 vgl->realtime_track = NULL;
a7023a1b 681#endif // VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952 682
a7023a1b 683 vik_layer_set_defaults ( VIK_LAYER(vgl), vp );
99163c34 684
b364d6bc
QT
685 return vgl;
686}
687
45c5ac8e 688static void vik_gps_layer_draw ( VikGpsLayer *vgl, VikViewport *vp )
b364d6bc
QT
689{
690 gint i;
b87d3952 691 VikLayer *vl;
45c5ac8e 692 VikLayer *trigger = VIK_LAYER(vik_viewport_get_trigger( vp ));
b364d6bc
QT
693
694 for (i = 0; i < NUM_TRW; i++) {
b87d3952
QT
695 vl = VIK_LAYER(vgl->trw_children[i]);
696 if (vl == trigger) {
45c5ac8e
RN
697 if ( vik_viewport_get_half_drawn ( vp ) ) {
698 vik_viewport_set_half_drawn ( vp, FALSE );
699 vik_viewport_snapshot_load( vp );
b87d3952 700 } else {
45c5ac8e 701 vik_viewport_snapshot_save( vp );
b87d3952
QT
702 }
703 }
45c5ac8e
RN
704 if (!vik_viewport_get_half_drawn(vp))
705 vik_layer_draw ( vl, vp );
b87d3952 706 }
728db5b5 707#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b87d3952
QT
708 if (vgl->realtime_tracking) {
709 if (VIK_LAYER(vgl) == trigger) {
45c5ac8e
RN
710 if ( vik_viewport_get_half_drawn ( vp ) ) {
711 vik_viewport_set_half_drawn ( vp, FALSE );
712 vik_viewport_snapshot_load( vp );
b87d3952 713 } else {
45c5ac8e 714 vik_viewport_snapshot_save( vp );
b87d3952
QT
715 }
716 }
45c5ac8e
RN
717 if (!vik_viewport_get_half_drawn(vp))
718 realtime_tracking_draw(vgl, vp);
b364d6bc 719 }
001a86db 720#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc
QT
721}
722
723static void gps_layer_change_coord_mode ( VikGpsLayer *vgl, VikCoordMode mode )
724{
725 gint i;
726 for (i = 0; i < NUM_TRW; i++) {
2cebc318 727 vik_layer_change_coord_mode(VIK_LAYER(vgl->trw_children[i]), mode);
b364d6bc
QT
728 }
729}
730
731static void gps_layer_add_menu_items( VikGpsLayer *vgl, GtkMenu *menu, gpointer vlp )
732{
733 static gpointer pass_along[2];
734 GtkWidget *item;
735 pass_along[0] = vgl;
736 pass_along[1] = vlp;
737
738 item = gtk_menu_item_new();
739 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
740 gtk_widget_show ( item );
741
d6de71f9
RN
742 /* Now with icons */
743 item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS") );
744 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
b364d6bc
QT
745 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_upload_cb), pass_along );
746 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
747 gtk_widget_show ( item );
748
d6de71f9
RN
749 item = gtk_image_menu_item_new_with_mnemonic ( _("Download from _GPS") );
750 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU) );
b364d6bc
QT
751 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_download_cb), pass_along );
752 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
753 gtk_widget_show ( item );
754
728db5b5 755#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
d6de71f9
RN
756 item = gtk_image_menu_item_new_with_mnemonic ( vgl->realtime_tracking ?
757 "_Stop Realtime Tracking" :
758 "_Start Realtime Tracking" );
759 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, vgl->realtime_tracking ?
760 gtk_image_new_from_stock (GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_MENU) :
761 gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU) );
b87d3952
QT
762 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_start_stop_tracking_cb), pass_along );
763 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
764 gtk_widget_show ( item );
765
700b0908
QT
766 item = gtk_menu_item_new();
767 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
768 gtk_widget_show ( item );
22d1e285 769
d6de71f9
RN
770 item = gtk_image_menu_item_new_with_mnemonic ( _("Empty _Realtime") );
771 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
22d1e285
RN
772 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_realtime_cb), pass_along );
773 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
774 gtk_widget_show ( item );
001a86db 775#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
700b0908 776
d6de71f9
RN
777 item = gtk_image_menu_item_new_with_mnemonic ( _("E_mpty Upload") );
778 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
700b0908
QT
779 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_upload_cb), pass_along );
780 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
781 gtk_widget_show ( item );
782
d6de71f9
RN
783 item = gtk_image_menu_item_new_with_mnemonic ( _("_Empty Download") );
784 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
700b0908
QT
785 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_download_cb), pass_along );
786 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
787 gtk_widget_show ( item );
788
d6de71f9
RN
789 item = gtk_image_menu_item_new_with_mnemonic ( _("Empty _All") );
790 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
700b0908
QT
791 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_all_cb), pass_along );
792 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
793 gtk_widget_show ( item );
794
b364d6bc
QT
795}
796
797static void disconnect_layer_signal ( VikLayer *vl, VikGpsLayer *vgl )
798{
325af20b 799 guint number_handlers = g_signal_handlers_disconnect_matched(vl, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, vgl);
30a9c13f 800 if ( number_handlers != 1 ) {
325af20b 801 g_critical(_("Unexpected number of disconnected handlers: %d"), number_handlers);
30a9c13f 802 }
b364d6bc
QT
803}
804
fdca5edb 805static void vik_gps_layer_free ( VikGpsLayer *vgl )
b364d6bc 806{
b364d6bc
QT
807 gint i;
808 for (i = 0; i < NUM_TRW; i++) {
e03074ba 809 if (vgl->vl.realized)
fdca5edb 810 disconnect_layer_signal(VIK_LAYER(vgl->trw_children[i]), vgl);
b364d6bc
QT
811 g_object_unref(vgl->trw_children[i]);
812 }
728db5b5 813#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
e92cb4e5 814 rt_gpsd_disconnect(vgl);
b87d3952
QT
815 if (vgl->realtime_track_gc != NULL)
816 g_object_unref(vgl->realtime_track_gc);
817 if (vgl->realtime_track_bg_gc != NULL)
818 g_object_unref(vgl->realtime_track_bg_gc);
819 if (vgl->realtime_track_pt1_gc != NULL)
820 g_object_unref(vgl->realtime_track_pt1_gc);
821 if (vgl->realtime_track_pt2_gc != NULL)
822 g_object_unref(vgl->realtime_track_pt2_gc);
001a86db 823#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc
QT
824}
825
fdca5edb 826static void vik_gps_layer_realize ( VikGpsLayer *vgl, VikTreeview *vt, GtkTreeIter *layer_iter )
b364d6bc
QT
827{
828 GtkTreeIter iter;
829 int ix;
830
5f955595
RN
831 // TODO set to garmin by default
832 //if (a_babel_device_list)
833 // device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
834 // Need to access uibuild widgets somehow....
835
b364d6bc 836 for (ix = 0; ix < NUM_TRW; ix++) {
fdca5edb 837 VikLayer * trw = VIK_LAYER(vgl->trw_children[ix]);
b364d6bc 838 vik_treeview_add_layer ( VIK_LAYER(vgl)->vt, layer_iter, &iter,
c3a02429 839 _(trw_names[ix]), vgl, TRUE,
b364d6bc
QT
840 trw, trw->type, trw->type );
841 if ( ! trw->visible )
842 vik_treeview_item_set_visible ( VIK_LAYER(vgl)->vt, &iter, FALSE );
843 vik_layer_realize ( trw, VIK_LAYER(vgl)->vt, &iter );
b87d3952 844 g_signal_connect_swapped ( G_OBJECT(trw), "update", G_CALLBACK(vik_layer_emit_update_secondary), vgl );
b364d6bc
QT
845 }
846}
847
7886de28
QT
848const GList *vik_gps_layer_get_children ( VikGpsLayer *vgl )
849{
850 int i;
851
852 if (vgl->children == NULL) {
853 for (i = NUM_TRW - 1; i >= 0; i--)
854 vgl->children = g_list_prepend(vgl->children, vgl->trw_children[i]);
855 }
856 return vgl->children;
857}
858
f253a6a6
QT
859VikTrwLayer * vik_gps_layer_get_a_child(VikGpsLayer *vgl)
860{
861 g_assert ((vgl->cur_read_child >= 0) && (vgl->cur_read_child < NUM_TRW));
862
863 VikTrwLayer * vtl = vgl->trw_children[vgl->cur_read_child];
864 if (++(vgl->cur_read_child) >= NUM_TRW)
865 vgl->cur_read_child = 0;
866 return(vtl);
867}
868
7886de28
QT
869gboolean vik_gps_layer_is_empty ( VikGpsLayer *vgl )
870{
871 if ( vgl->trw_children[0] )
872 return FALSE;
873 return TRUE;
874}
875
b364d6bc
QT
876static void gps_session_delete(GpsSession *sess)
877{
fc6640a9 878 vik_mutex_free(sess->mutex);
b364d6bc 879 g_free(sess->cmd_args);
b364d6bc 880 g_free(sess);
b364d6bc
QT
881}
882
883static void set_total_count(gint cnt, GpsSession *sess)
884{
885 gchar s[128];
886 gdk_threads_enter();
887 g_mutex_lock(sess->mutex);
888 if (sess->ok) {
97634600
GB
889 const gchar *tmp_str;
890 if (sess->direction == GPS_DOWN)
891 {
0d2b891f
RN
892 switch (sess->progress_type) {
893 case WPT: tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt); sess->total_count = cnt; break;
894 case TRK: tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt); sess->total_count = cnt; break;
895 default:
896 {
897 // 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
898 gint mycnt = (cnt / 2) + 1;
899 tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", mycnt); break;
900 sess->total_count = mycnt;
901 }
902 }
97634600 903 }
0d2b891f 904 else
97634600 905 {
0d2b891f
RN
906 switch (sess->progress_type) {
907 case WPT: tmp_str = ngettext("Uploading %d waypoint...", "Uploading %d waypoints...", cnt); break;
908 case TRK: tmp_str = ngettext("Uploading %d trackpoint...", "Uploading %d trackpoints...", cnt); break;
909 default: tmp_str = ngettext("Uploading %d routepoint...", "Uploading %d routepoints...", cnt); break;
910 }
97634600
GB
911 }
912
913 g_snprintf(s, 128, tmp_str, cnt);
b364d6bc
QT
914 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
915 gtk_widget_show ( sess->progress_label );
916 sess->total_count = cnt;
917 }
918 g_mutex_unlock(sess->mutex);
919 gdk_threads_leave();
920}
921
922static void set_current_count(gint cnt, GpsSession *sess)
923{
924 gchar s[128];
97634600 925 const gchar *tmp_str;
b364d6bc
QT
926
927 gdk_threads_enter();
928 g_mutex_lock(sess->mutex);
929 if (sess->ok) {
930 if (cnt < sess->total_count) {
97634600
GB
931 if (sess->direction == GPS_DOWN)
932 {
0d2b891f
RN
933 switch (sess->progress_type) {
934 case WPT: tmp_str = ngettext("Downloaded %d out of %d waypoint...", "Downloaded %d out of %d waypoints...", sess->total_count); break;
935 case TRK: tmp_str = ngettext("Downloaded %d out of %d trackpoint...", "Downloaded %d out of %d trackpoints...", sess->total_count); break;
936 default: tmp_str = ngettext("Downloaded %d out of %d routepoint...", "Downloaded %d out of %d routepoints...", sess->total_count); break;
937 }
97634600
GB
938 }
939 else {
0d2b891f
RN
940 switch (sess->progress_type) {
941 case WPT: tmp_str = ngettext("Uploaded %d out of %d waypoint...", "Uploaded %d out of %d waypoints...", sess->total_count); break;
942 case TRK: tmp_str = ngettext("Uploaded %d out of %d trackpoint...", "Uploaded %d out of %d trackpoints...", sess->total_count); break;
943 default: tmp_str = ngettext("Uploaded %d out of %d routepoint...", "Uploaded %d out of %d routepoints...", sess->total_count); break;
944 }
97634600
GB
945 }
946 g_snprintf(s, 128, tmp_str, cnt, sess->total_count);
b364d6bc 947 } else {
97634600
GB
948 if (sess->direction == GPS_DOWN)
949 {
0d2b891f
RN
950 switch (sess->progress_type) {
951 case WPT: tmp_str = ngettext("Downloaded %d waypoint", "Downloaded %d waypoints", cnt); break;
952 case TRK: tmp_str = ngettext("Downloaded %d trackpoint", "Downloaded %d trackpoints", cnt); break;
953 default: tmp_str = ngettext("Downloaded %d routepoint", "Downloaded %d routepoints", cnt); break;
954 }
97634600
GB
955 }
956 else {
0d2b891f
RN
957 switch (sess->progress_type) {
958 case WPT: tmp_str = ngettext("Uploaded %d waypoint", "Uploaded %d waypoints", cnt); break;
959 case TRK: tmp_str = ngettext("Uploaded %d trackpoint", "Uploaded %d trackpoints", cnt); break;
960 default: tmp_str = ngettext("Uploaded %d routepoint", "Uploaded %d routepoints", cnt); break;
961 }
97634600
GB
962 }
963 g_snprintf(s, 128, tmp_str, cnt);
b364d6bc
QT
964 }
965 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
966 }
967 g_mutex_unlock(sess->mutex);
968 gdk_threads_leave();
969}
970
971static void set_gps_info(const gchar *info, GpsSession *sess)
972{
973 gchar s[256];
974 gdk_threads_enter();
975 g_mutex_lock(sess->mutex);
976 if (sess->ok) {
97634600 977 g_snprintf(s, 256, _("GPS Device: %s"), info);
b364d6bc
QT
978 gtk_label_set_text ( GTK_LABEL(sess->gps_label), s );
979 }
980 g_mutex_unlock(sess->mutex);
981 gdk_threads_leave();
982}
983
c011c859
RN
984/*
985 * Common processing for GPS Device information
986 * It doesn't matter whether we're uploading or downloading
987 */
988static void process_line_for_gps_info ( const gchar *line, GpsSession *sess )
989{
990 if (strstr(line, "PRDDAT")) {
991 gchar **tokens = g_strsplit(line, " ", 0);
992 gchar info[128];
993 int ilen = 0;
994 int i;
995 int n_tokens = 0;
996
997 while (tokens[n_tokens])
998 n_tokens++;
999
1000 // I'm not entirely clear what information this is trying to get...
1001 // Obviously trying to decipher some kind of text/naming scheme
1002 // Anyway this will be superceded if there is 'Unit:' information
1003 if (n_tokens > 8) {
1004 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
1005 guint ch;
1006 sscanf(tokens[i], "%x", &ch);
1007 info[ilen++] = ch;
1008 }
1009 info[ilen++] = 0;
1010 set_gps_info(info, sess);
1011 }
1012 g_strfreev(tokens);
1013 }
1014
1015 /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
1016 if (strstr(line, "Unit:")) {
1017 gchar **tokens = g_strsplit(line, "\t", 0);
1018 int n_tokens = 0;
1019 while (tokens[n_tokens])
1020 n_tokens++;
1021
1022 if (n_tokens > 1) {
1023 set_gps_info(tokens[1], sess);
1024 }
1025 g_strfreev(tokens);
1026 }
1027}
1028
b364d6bc
QT
1029static void gps_download_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
1030{
1031 gchar *line;
1032
1033 gdk_threads_enter ();
1034 g_mutex_lock(sess->mutex);
1035 if (!sess->ok) {
1036 g_mutex_unlock(sess->mutex);
1037 gps_session_delete(sess);
1038 gdk_threads_leave();
1039 g_thread_exit ( NULL );
1040 }
1041 g_mutex_unlock(sess->mutex);
1042 gdk_threads_leave ();
1043
1044 switch(c) {
1045 case BABEL_DIAG_OUTPUT:
1046 line = (gchar *)data;
1047
8d0586c6
RN
1048 gdk_threads_enter();
1049 g_mutex_lock(sess->mutex);
1050 if (sess->ok) {
1051 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
1052 }
1053 g_mutex_unlock(sess->mutex);
1054 gdk_threads_leave();
1055
0d2b891f
RN
1056 /* tells us the type of items that will follow */
1057 if (strstr(line, "Xfer Wpt")) {
b364d6bc 1058 sess->progress_label = sess->wp_label;
0d2b891f 1059 sess->progress_type = WPT;
b364d6bc 1060 }
0d2b891f 1061 if (strstr(line, "Xfer Trk")) {
b364d6bc 1062 sess->progress_label = sess->trk_label;
0d2b891f 1063 sess->progress_type = TRK;
b364d6bc 1064 }
0d2b891f
RN
1065 if (strstr(line, "Xfer Rte")) {
1066 sess->progress_label = sess->rte_label;
1067 sess->progress_type = RTE;
1068 }
1069
c011c859
RN
1070 process_line_for_gps_info ( line, sess );
1071
0d2b891f 1072 if (strstr(line, "RECORD")) {
b364d6bc
QT
1073 int lsb, msb, cnt;
1074
c83b5ad9
QT
1075 if (strlen(line) > 20) {
1076 sscanf(line+17, "%x", &lsb);
1077 sscanf(line+20, "%x", &msb);
1078 cnt = lsb + msb * 256;
1079 set_total_count(cnt, sess);
1080 sess->count = 0;
1081 }
b364d6bc 1082 }
0d2b891f 1083 if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
b364d6bc
QT
1084 sess->count++;
1085 set_current_count(sess->count, sess);
1086 }
1087 break;
1088 case BABEL_DONE:
1089 break;
1090 default:
1091 break;
1092 }
1093
1094}
1095
1096static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
1097{
1098 gchar *line;
1099 static int cnt = 0;
1100
1101 gdk_threads_enter ();
1102 g_mutex_lock(sess->mutex);
1103 if (!sess->ok) {
1104 g_mutex_unlock(sess->mutex);
1105 gps_session_delete(sess);
1106 gdk_threads_leave();
1107 g_thread_exit ( NULL );
1108 }
1109 g_mutex_unlock(sess->mutex);
1110 gdk_threads_leave ();
1111
1112 switch(c) {
1113 case BABEL_DIAG_OUTPUT:
1114 line = (gchar *)data;
1115
8d0586c6
RN
1116 gdk_threads_enter();
1117 g_mutex_lock(sess->mutex);
1118 if (sess->ok) {
1119 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
1120 }
1121 g_mutex_unlock(sess->mutex);
1122 gdk_threads_leave();
1123
c011c859
RN
1124 process_line_for_gps_info ( line, sess );
1125
b364d6bc
QT
1126 if (strstr(line, "RECORD")) {
1127 int lsb, msb;
1128
c83b5ad9
QT
1129 if (strlen(line) > 20) {
1130 sscanf(line+17, "%x", &lsb);
1131 sscanf(line+20, "%x", &msb);
1132 cnt = lsb + msb * 256;
1133 /* set_total_count(cnt, sess); */
1134 sess->count = 0;
1135 }
b364d6bc
QT
1136 }
1137 if ( strstr(line, "WPTDAT")) {
1138 if (sess->count == 0) {
1139 sess->progress_label = sess->wp_label;
0d2b891f 1140 sess->progress_type = WPT;
b364d6bc
QT
1141 set_total_count(cnt, sess);
1142 }
1143 sess->count++;
1144 set_current_count(sess->count, sess);
0d2b891f
RN
1145 }
1146 if ( strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
1147 if (sess->count == 0) {
1148 sess->progress_label = sess->rte_label;
1149 sess->progress_type = RTE;
1150 // 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
1151 // Anyway since we're uploading - we should know how many points we're going to put!
1152 cnt = (cnt / 2) + 1;
1153 set_total_count(cnt, sess);
1154 }
1155 sess->count++;
1156 set_current_count(sess->count, sess);
b364d6bc
QT
1157 }
1158 if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
1159 if (sess->count == 0) {
1160 sess->progress_label = sess->trk_label;
0d2b891f 1161 sess->progress_type = TRK;
b364d6bc
QT
1162 set_total_count(cnt, sess);
1163 }
1164 sess->count++;
1165 set_current_count(sess->count, sess);
1166 }
1167 break;
1168 case BABEL_DONE:
1169 break;
1170 default:
1171 break;
1172 }
1173
1174}
1175
1176static void gps_comm_thread(GpsSession *sess)
1177{
1178 gboolean result;
1179
1180 if (sess->direction == GPS_DOWN)
9181183a 1181 result = a_babel_convert_from (sess->vtl, sess->cmd_args, sess->port,
ed691ed1 1182 (BabelStatusFunc) gps_download_progress_func, sess, NULL);
10aa2b84 1183 else {
778f41c5 1184 result = a_babel_convert_to (sess->vtl, sess->track, sess->cmd_args, sess->port,
9181183a 1185 (BabelStatusFunc) gps_upload_progress_func, sess);
10aa2b84 1186 }
b364d6bc 1187
b364d6bc 1188 if (!result) {
4c77d5e0 1189 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Error: couldn't find gpsbabel.") );
b364d6bc
QT
1190 }
1191 else {
1192 g_mutex_lock(sess->mutex);
1193 if (sess->ok) {
4c77d5e0 1194 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Done.") );
b364d6bc
QT
1195 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT, TRUE );
1196 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_REJECT, FALSE );
b870a512
RN
1197
1198 /* Do not change the view if we are following the current GPS position */
728db5b5 1199#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b870a512
RN
1200 if (!sess->realtime_tracking)
1201#endif
1202 {
2eb89de4 1203 if ( sess->vvp && sess->direction == GPS_DOWN ) {
b870a512
RN
1204 /* View the data available */
1205 vik_trw_layer_auto_set_view ( sess->vtl, sess->vvp) ;
da121f9b 1206 vik_layer_emit_update ( VIK_LAYER(sess->vtl) ); // NB update from background thread
b870a512
RN
1207 }
1208 }
b364d6bc
QT
1209 } else {
1210 /* canceled */
1211 }
1212 g_mutex_unlock(sess->mutex);
1213 }
1214
1215 g_mutex_lock(sess->mutex);
1216 if (sess->ok) {
1217 sess->ok = FALSE;
1218 g_mutex_unlock(sess->mutex);
1219 }
1220 else {
1221 g_mutex_unlock(sess->mutex);
1222 gps_session_delete(sess);
1223 }
b364d6bc
QT
1224 g_thread_exit(NULL);
1225}
1226
e4b02b41
RN
1227/**
1228 * vik_gps_comm:
eebf8102
RN
1229 * @vtl: The TrackWaypoint layer to operate on
1230 * @track: Operate on a particular track when specified
1231 * @dir: The direction of the transfer
1232 * @protocol: The GPS device communication protocol
1233 * @port: The GPS serial port
1234 * @tracking: If tracking then viewport display update will be skipped
1235 * @vvp: A viewport is required as the display may get updated
1236 * @vlp: A layers panel is needed for uploading as the items maybe modified
1237 * @do_tracks: Whether tracks shoud be processed
1238 * @do_waypoints: Whether waypoints shoud be processed
1239 * @turn_off: Whether we should attempt to turn off the GPS device after the transfer (only some devices support this)
e4b02b41
RN
1240 *
1241 * Talk to a GPS Device using a thread which updates a dialog with the progress
1242 */
1243gint vik_gps_comm ( VikTrwLayer *vtl,
778f41c5 1244 VikTrack *track,
e4b02b41
RN
1245 vik_gps_dir dir,
1246 gchar *protocol,
1247 gchar *port,
1248 gboolean tracking,
1249 VikViewport *vvp,
1250 VikLayersPanel *vlp,
1251 gboolean do_tracks,
0d2b891f 1252 gboolean do_routes,
eebf8102
RN
1253 gboolean do_waypoints,
1254 gboolean turn_off )
e4b02b41 1255{
b364d6bc 1256 GpsSession *sess = g_malloc(sizeof(GpsSession));
d6c58ab9 1257 char *tracks = NULL;
0d2b891f 1258 char *routes = NULL;
d6c58ab9 1259 char *waypoints = NULL;
b364d6bc 1260
fc6640a9 1261 sess->mutex = vik_mutex_new();
b364d6bc
QT
1262 sess->direction = dir;
1263 sess->vtl = vtl;
778f41c5 1264 sess->track = track;
b364d6bc
QT
1265 sess->port = g_strdup(port);
1266 sess->ok = TRUE;
4c77d5e0 1267 sess->window_title = (dir == GPS_DOWN) ? _("GPS Download") : _("GPS Upload");
b870a512 1268 sess->vvp = vvp;
bc950037
RN
1269
1270 // This must be done inside the main thread as the uniquify causes screen updates
1271 // (originally performed this nearer the point of upload in the thread)
1272 if ( dir == GPS_UP ) {
1273 // Enforce unique names in the layer upload to the GPS device
1274 // NB this may only be a Garmin device restriction (and may be not every Garmin device either...)
1275 // Thus this maintains the older code in built restriction
1276 if ( ! vik_trw_layer_uniquify ( sess->vtl, vlp ) )
1277 vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(sess->vtl))), VIK_STATUSBAR_INFO,
1278 _("Warning - GPS Upload items may overwrite each other") );
1279 }
1280
728db5b5 1281#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b870a512
RN
1282 sess->realtime_tracking = tracking;
1283#endif
d6c58ab9
RN
1284
1285 if (do_tracks)
1286 tracks = "-t";
1287 else
1288 tracks = "";
0d2b891f
RN
1289 if (do_routes)
1290 routes = "-r";
1291 else
1292 routes = "";
d6c58ab9
RN
1293 if (do_waypoints)
1294 waypoints = "-w";
1295 else
1296 waypoints = "";
1297
0d2b891f
RN
1298 sess->cmd_args = g_strdup_printf("-D 9 %s %s %s -%c %s",
1299 tracks, routes, waypoints, (dir == GPS_DOWN) ? 'i' : 'o', protocol);
d6c58ab9
RN
1300 tracks = NULL;
1301 waypoints = NULL;
1302
e5f73681 1303 // Only create dialog if we're going to do some transferring
0d2b891f 1304 if ( do_tracks || do_waypoints || do_routes ) {
e5f73681
RN
1305 sess->dialog = gtk_dialog_new_with_buttons ( "", VIK_GTK_WINDOW_FROM_LAYER(vtl), 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
1306 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog),
1307 GTK_RESPONSE_ACCEPT, FALSE );
1308 gtk_window_set_title ( GTK_WINDOW(sess->dialog), sess->window_title );
b364d6bc 1309
e5f73681 1310 sess->status_label = gtk_label_new (_("Status: detecting gpsbabel"));
9b082b39 1311 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->status_label, FALSE, FALSE, 5 );
e5f73681 1312 gtk_widget_show_all(sess->status_label);
b364d6bc 1313
e5f73681
RN
1314 sess->gps_label = gtk_label_new (_("GPS device: N/A"));
1315 sess->ver_label = gtk_label_new ("");
1316 sess->id_label = gtk_label_new ("");
1317 sess->wp_label = gtk_label_new ("");
1318 sess->trk_label = gtk_label_new ("");
0d2b891f 1319 sess->rte_label = gtk_label_new ("");
b364d6bc 1320
9b082b39
RN
1321 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->gps_label, FALSE, FALSE, 5 );
1322 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->wp_label, FALSE, FALSE, 5 );
1323 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->trk_label, FALSE, FALSE, 5 );
1324 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->rte_label, FALSE, FALSE, 5 );
b364d6bc 1325
e5f73681 1326 gtk_widget_show_all(sess->dialog);
b364d6bc 1327
e5f73681
RN
1328 sess->progress_label = sess->wp_label;
1329 sess->total_count = -1;
b364d6bc 1330
e5f73681 1331 // Starting gps read/write thread
b832ea69
RN
1332#if GLIB_CHECK_VERSION (2, 32, 0)
1333 g_thread_try_new ( "gps_comm_thread", (GThreadFunc)gps_comm_thread, sess, NULL );
1334#else
1335 g_thread_create ( (GThreadFunc)gps_comm_thread, sess, FALSE, NULL );
1336#endif
b364d6bc 1337
e5f73681
RN
1338 gtk_dialog_set_default_response ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT );
1339 gtk_dialog_run(GTK_DIALOG(sess->dialog));
b364d6bc 1340
e5f73681
RN
1341 gtk_widget_destroy(sess->dialog);
1342 }
1343 else {
1344 if ( !turn_off )
1345 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No GPS items selected for transfer.") );
1346 }
b364d6bc
QT
1347
1348 g_mutex_lock(sess->mutex);
e5f73681 1349
b364d6bc
QT
1350 if (sess->ok) {
1351 sess->ok = FALSE; /* tell thread to stop */
1352 g_mutex_unlock(sess->mutex);
1353 }
1354 else {
eebf8102
RN
1355 if ( turn_off ) {
1356 // No need for thread for powering off device (should be quick operation...) - so use babel command directly:
1357 gchar *device_off = g_strdup_printf("-i %s,%s", protocol, "power_off");
ed691ed1 1358 gboolean result = a_babel_convert_from (NULL, (const char*)device_off, (const char*)port, NULL, NULL, NULL);
eebf8102
RN
1359 if ( !result )
1360 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not turn off device.") );
1361 g_free ( device_off );
1362 }
b364d6bc
QT
1363 g_mutex_unlock(sess->mutex);
1364 gps_session_delete(sess);
1365 }
1366
b364d6bc
QT
1367 return 0;
1368}
1369
1370static void gps_upload_cb( gpointer layer_and_vlp[2] )
1371{
1372 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
10aa2b84 1373 VikLayersPanel *vlp = VIK_LAYERS_PANEL(layer_and_vlp[1]);
b364d6bc 1374 VikTrwLayer *vtl = vgl->trw_children[TRW_UPLOAD];
2eb89de4
RN
1375 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1376 VikViewport *vvp = vik_window_viewport(vw);
0d2b891f 1377 vik_gps_comm(vtl, NULL, GPS_UP, vgl->protocol, vgl->serial_port, FALSE, vvp, vlp, vgl->upload_tracks, vgl->upload_routes, vgl->upload_waypoints, FALSE);
b364d6bc
QT
1378}
1379
1380static void gps_download_cb( gpointer layer_and_vlp[2] )
1381{
1382 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1383 VikTrwLayer *vtl = vgl->trw_children[TRW_DOWNLOAD];
b870a512
RN
1384 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1385 VikViewport *vvp = vik_window_viewport(vw);
728db5b5 1386#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
0d2b891f 1387 vik_gps_comm(vtl, NULL, GPS_DOWN, vgl->protocol, vgl->serial_port, vgl->realtime_tracking, vvp, NULL, vgl->download_tracks, vgl->download_routes, vgl->download_waypoints, FALSE);
b870a512 1388#else
0d2b891f 1389 vik_gps_comm(vtl, NULL, GPS_DOWN, vgl->protocol, vgl->serial_port, FALSE, vvp, NULL, vgl->download_tracks, vgl->download_routes, vgl->download_waypoints, FALSE);
b870a512 1390#endif
b364d6bc 1391}
700b0908
QT
1392
1393static void gps_empty_upload_cb( gpointer layer_and_vlp[2] )
1394{
1395 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
a6a4825c
RN
1396 // Get confirmation from the user
1397 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1398 _("Are you sure you want to delete GPS Upload data?"),
1399 NULL ) )
1400 return;
700b0908
QT
1401 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
1402 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
0d2b891f 1403 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_UPLOAD]);
700b0908
QT
1404}
1405
1406static void gps_empty_download_cb( gpointer layer_and_vlp[2] )
1407{
1408 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
a6a4825c
RN
1409 // Get confirmation from the user
1410 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1411 _("Are you sure you want to delete GPS Download data?"),
1412 NULL ) )
1413 return;
700b0908
QT
1414 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
1415 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
0d2b891f 1416 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_DOWNLOAD]);
700b0908
QT
1417}
1418
728db5b5 1419#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
22d1e285
RN
1420static void gps_empty_realtime_cb( gpointer layer_and_vlp[2] )
1421{
1422 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
a6a4825c
RN
1423 // Get confirmation from the user
1424 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1425 _("Are you sure you want to delete GPS Realtime data?"),
1426 NULL ) )
1427 return;
22d1e285
RN
1428 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_REALTIME]);
1429 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_REALTIME]);
1430}
1431#endif
1432
700b0908
QT
1433static void gps_empty_all_cb( gpointer layer_and_vlp[2] )
1434{
1435 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
a6a4825c
RN
1436 // Get confirmation from the user
1437 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1438 _("Are you sure you want to delete All GPS data?"),
1439 NULL ) )
1440 return;
700b0908
QT
1441 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
1442 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
0d2b891f 1443 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_UPLOAD]);
700b0908
QT
1444 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
1445 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
0d2b891f 1446 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_DOWNLOAD]);
728db5b5 1447#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
dfef116b
RN
1448 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_REALTIME]);
1449 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_REALTIME]);
1450#endif
700b0908 1451}
b87d3952 1452
728db5b5 1453#if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
b87d3952
QT
1454static void realtime_tracking_draw(VikGpsLayer *vgl, VikViewport *vp)
1455{
c4e61875 1456 struct LatLon ll;
b87d3952
QT
1457 VikCoord nw, se;
1458 struct LatLon lnw, lse;
1459 vik_viewport_screen_to_coord ( vp, -20, -20, &nw );
1460 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp)+20, vik_viewport_get_width(vp)+20, &se );
1461 vik_coord_to_latlon ( &nw, &lnw );
1462 vik_coord_to_latlon ( &se, &lse );
c4e61875
QT
1463 if ( vgl->realtime_fix.fix.latitude > lse.lat &&
1464 vgl->realtime_fix.fix.latitude < lnw.lat &&
1465 vgl->realtime_fix.fix.longitude > lnw.lon &&
7888d76f
RN
1466 vgl->realtime_fix.fix.longitude < lse.lon &&
1467 !isnan (vgl->realtime_fix.fix.track) ) {
b87d3952
QT
1468 VikCoord gps;
1469 gint x, y;
1470 gint half_back_x, half_back_y;
1471 gint half_back_bg_x, half_back_bg_y;
1472 gint pt_x, pt_y;
8b15d148 1473 gint ptbg_x;
b87d3952
QT
1474 gint side1_x, side1_y, side2_x, side2_y;
1475 gint side1bg_x, side1bg_y, side2bg_x, side2bg_y;
1476
c4e61875
QT
1477 ll.lat = vgl->realtime_fix.fix.latitude;
1478 ll.lon = vgl->realtime_fix.fix.longitude;
1479 vik_coord_load_from_latlon ( &gps, vik_viewport_get_coord_mode(vp), &ll);
b87d3952
QT
1480 vik_viewport_coord_to_screen ( vp, &gps, &x, &y );
1481
0da53bd9
GB
1482 gdouble heading_cos = cos(DEG2RAD(vgl->realtime_fix.fix.track));
1483 gdouble heading_sin = sin(DEG2RAD(vgl->realtime_fix.fix.track));
b87d3952
QT
1484
1485 half_back_y = y+8*heading_cos;
1486 half_back_x = x-8*heading_sin;
1487 half_back_bg_y = y+10*heading_cos;
1488 half_back_bg_x = x-10*heading_sin;
1489
1490 pt_y = half_back_y-24*heading_cos;
1491 pt_x = half_back_x+24*heading_sin;
8b15d148 1492 //ptbg_y = half_back_bg_y-28*heading_cos;
b87d3952
QT
1493 ptbg_x = half_back_bg_x+28*heading_sin;
1494
1495 side1_y = half_back_y+9*heading_sin;
1496 side1_x = half_back_x+9*heading_cos;
1497 side1bg_y = half_back_bg_y+11*heading_sin;
1498 side1bg_x = half_back_bg_x+11*heading_cos;
1499
1500 side2_y = half_back_y-9*heading_sin;
1501 side2_x = half_back_x-9*heading_cos;
1502 side2bg_y = half_back_bg_y-11*heading_sin;
1503 side2bg_x = half_back_bg_x-11*heading_cos;
1504
1505 GdkPoint trian[3] = { { pt_x, pt_y }, {side1_x, side1_y}, {side2_x, side2_y} };
1506 GdkPoint trian_bg[3] = { { ptbg_x, pt_y }, {side1bg_x, side1bg_y}, {side2bg_x, side2bg_y} };
1507
1508 vik_viewport_draw_polygon ( vp, vgl->realtime_track_bg_gc, TRUE, trian_bg, 3 );
1509 vik_viewport_draw_polygon ( vp, vgl->realtime_track_gc, TRUE, trian, 3 );
c4e61875
QT
1510 vik_viewport_draw_rectangle ( vp,
1511 (vgl->realtime_fix.fix.mode > MODE_2D) ? vgl->realtime_track_pt2_gc : vgl->realtime_track_pt1_gc,
1512 TRUE, x-2, y-2, 4, 4 );
1513 //vgl->realtime_track_pt_gc = (vgl->realtime_track_pt_gc == vgl->realtime_track_pt1_gc) ? vgl->realtime_track_pt2_gc : vgl->realtime_track_pt1_gc;
b87d3952
QT
1514 }
1515}
1516
8b5838b2 1517static VikTrackpoint* create_realtime_trackpoint(VikGpsLayer *vgl, gboolean forced)
b87d3952 1518{
c4e61875
QT
1519 struct LatLon ll;
1520 GList *last_tp;
97cab2d5
QT
1521
1522 /* Note that fix.time is a double, but it should not affect the precision
1523 for most GPS */
1524 time_t cur_timestamp = vgl->realtime_fix.fix.time;
1525 time_t last_timestamp = vgl->last_fix.fix.time;
1526
1527 if (cur_timestamp < last_timestamp) {
8b5838b2 1528 return NULL;
97cab2d5
QT
1529 }
1530
b87d3952 1531 if (vgl->realtime_record && vgl->realtime_fix.dirty) {
c4e61875 1532 gboolean replace = FALSE;
7888d76f
RN
1533 int heading = isnan(vgl->realtime_fix.fix.track) ? 0 : (int)floor(vgl->realtime_fix.fix.track);
1534 int last_heading = isnan(vgl->last_fix.fix.track) ? 0 : (int)floor(vgl->last_fix.fix.track);
c4e61875
QT
1535 int alt = isnan(vgl->realtime_fix.fix.altitude) ? VIK_DEFAULT_ALTITUDE : floor(vgl->realtime_fix.fix.altitude);
1536 int last_alt = isnan(vgl->last_fix.fix.altitude) ? VIK_DEFAULT_ALTITUDE : floor(vgl->last_fix.fix.altitude);
1537 if (((last_tp = g_list_last(vgl->realtime_track->trackpoints)) != NULL) &&
1538 (vgl->realtime_fix.fix.mode > MODE_2D) &&
1539 (vgl->last_fix.fix.mode <= MODE_2D) &&
97cab2d5 1540 ((cur_timestamp - last_timestamp) < 2)) {
c4e61875
QT
1541 g_free(last_tp->data);
1542 vgl->realtime_track->trackpoints = g_list_delete_link(vgl->realtime_track->trackpoints, last_tp);
1543 replace = TRUE;
1544 }
97cab2d5
QT
1545 if (replace ||
1546 ((cur_timestamp != last_timestamp) &&
1547 ((forced ||
1548 ((heading < last_heading) && (heading < (last_heading - 3))) ||
1549 ((heading > last_heading) && (heading > (last_heading + 3))) ||
1550 ((alt != VIK_DEFAULT_ALTITUDE) && (alt != last_alt)))))) {
b87d3952
QT
1551 /* TODO: check for new segments */
1552 VikTrackpoint *tp = vik_trackpoint_new();
1553 tp->newsegment = FALSE;
b87d3952 1554 tp->has_timestamp = TRUE;
c4e61875 1555 tp->timestamp = vgl->realtime_fix.fix.time;
a2817d3c
QT
1556 tp->altitude = alt;
1557 /* speed only available for 3D fix. Check for NAN when use this speed */
1558 tp->speed = vgl->realtime_fix.fix.speed;
1559 tp->course = vgl->realtime_fix.fix.track;
1560 tp->nsats = vgl->realtime_fix.satellites_used;
1561 tp->fix_mode = vgl->realtime_fix.fix.mode;
c4e61875
QT
1562
1563 ll.lat = vgl->realtime_fix.fix.latitude;
1564 ll.lon = vgl->realtime_fix.fix.longitude;
b87d3952 1565 vik_coord_load_from_latlon(&tp->coord,
c4e61875 1566 vik_trw_layer_get_coord_mode(vgl->trw_children[TRW_REALTIME]), &ll);
b87d3952 1567
9bc95d58 1568 vik_track_add_trackpoint ( vgl->realtime_track, tp, TRUE ); // Ensure bounds is recalculated
b87d3952 1569 vgl->realtime_fix.dirty = FALSE;
a2817d3c 1570 vgl->realtime_fix.satellites_used = 0;
b87d3952 1571 vgl->last_fix = vgl->realtime_fix;
8b5838b2 1572 return tp;
b87d3952
QT
1573 }
1574 }
8b5838b2
RN
1575 return NULL;
1576}
1577
1578#define VIK_SETTINGS_GPS_STATUSBAR_FORMAT "gps_statusbar_format"
1579
1580static void update_statusbar ( VikGpsLayer *vgl, VikWindow *vw )
1581{
1582 gchar *statusbar_format_code = NULL;
1583 gboolean need2free = FALSE;
1584 if ( !a_settings_get_string ( VIK_SETTINGS_GPS_STATUSBAR_FORMAT, &statusbar_format_code ) ) {
1585 // Otherwise use default
1586 statusbar_format_code = g_strdup ( "GSA" );
1587 need2free = TRUE;
1588 }
1589
fee4e142 1590 gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, vgl->trkpt, vgl->trkpt_prev, vgl->realtime_track, vgl->last_fix.fix.climb );
8b5838b2
RN
1591 vik_statusbar_set_message ( vik_window_get_statusbar (vw), VIK_STATUSBAR_INFO, msg );
1592 g_free ( msg );
1593
1594 if ( need2free )
1595 g_free ( statusbar_format_code );
b87d3952
QT
1596
1597}
1598
c5bc70c3 1599static void gpsd_raw_hook(VglGpsd *vgpsd, gchar *data)
b87d3952 1600{
c4e61875 1601 gboolean update_all = FALSE;
b87d3952
QT
1602 VikGpsLayer *vgl = vgpsd->vgl;
1603
c4e61875
QT
1604 if (!vgl->realtime_tracking) {
1605 g_warning("%s: receiving GPS data while not in realtime mode", __PRETTY_FUNCTION__);
b87d3952 1606 return;
b87d3952
QT
1607 }
1608
b87d3952
QT
1609 if ((vgpsd->gpsd.fix.mode >= MODE_2D) &&
1610 !isnan(vgpsd->gpsd.fix.latitude) &&
7888d76f 1611 !isnan(vgpsd->gpsd.fix.longitude)) {
dc3a1898
QT
1612
1613 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1614 VikViewport *vvp = vik_window_viewport(vw);
c4e61875 1615 vgl->realtime_fix.fix = vgpsd->gpsd.fix;
a2817d3c 1616 vgl->realtime_fix.satellites_used = vgpsd->gpsd.satellites_used;
b87d3952
QT
1617 vgl->realtime_fix.dirty = TRUE;
1618
dc3a1898
QT
1619 struct LatLon ll;
1620 VikCoord vehicle_coord;
c4e61875 1621
dc3a1898
QT
1622 ll.lat = vgl->realtime_fix.fix.latitude;
1623 ll.lon = vgl->realtime_fix.fix.longitude;
1624 vik_coord_load_from_latlon(&vehicle_coord,
1625 vik_trw_layer_get_coord_mode(vgl->trw_children[TRW_REALTIME]), &ll);
1626
1627 if ((vgl->vehicle_position == VEHICLE_POSITION_CENTERED) ||
c5bc70c3 1628 (vgl->realtime_jump_to_start && vgl->first_realtime_trackpoint)) {
be5554c5 1629 vik_viewport_set_center_coord(vvp, &vehicle_coord, FALSE);
dc3a1898
QT
1630 update_all = TRUE;
1631 }
a00e1e36 1632 else if (vgl->vehicle_position == VEHICLE_POSITION_ON_SCREEN) {
dc3a1898
QT
1633 const int hdiv = 6;
1634 const int vdiv = 6;
1635 const int px = 20; /* adjust ment in pixels to make sure vehicle is inside the box */
1636 gint width = vik_viewport_get_width(vvp);
1637 gint height = vik_viewport_get_height(vvp);
1638 gint vx, vy;
1639
1640 vik_viewport_coord_to_screen(vvp, &vehicle_coord, &vx, &vy);
c4e61875 1641 update_all = TRUE;
dc3a1898
QT
1642 if (vx < (width/hdiv))
1643 vik_viewport_set_center_screen(vvp, vx - width/2 + width/hdiv + px, vy);
1644 else if (vx > (width - width/hdiv))
1645 vik_viewport_set_center_screen(vvp, vx + width/2 - width/hdiv - px, vy);
1646 else if (vy < (height/vdiv))
1647 vik_viewport_set_center_screen(vvp, vx, vy - height/2 + height/vdiv + px);
1648 else if (vy > (height - height/vdiv))
1649 vik_viewport_set_center_screen(vvp, vx, vy + height/2 - height/vdiv - px);
1650 else
1651 update_all = FALSE;
c4e61875
QT
1652 }
1653
c5bc70c3 1654 vgl->first_realtime_trackpoint = FALSE;
8b5838b2
RN
1655
1656 vgl->trkpt = create_realtime_trackpoint ( vgl, FALSE );
1657
1658 if ( vgl->trkpt ) {
1659 if ( vgl->realtime_update_statusbar )
1660 update_statusbar ( vgl, vw );
1661 vgl->trkpt_prev = vgl->trkpt;
1662 }
b87d3952 1663
da121f9b 1664 vik_layer_emit_update ( update_all ? VIK_LAYER(vgl) : VIK_LAYER(vgl->trw_children[TRW_REALTIME]) ); // NB update from background thread
b87d3952
QT
1665 }
1666}
1667
1668static gboolean gpsd_data_available(GIOChannel *source, GIOCondition condition, gpointer data)
1669{
b87d3952 1670 VikGpsLayer *vgl = data;
c5bc70c3 1671 if (condition == G_IO_IN) {
bff27ab1
RN
1672#if GPSD_API_MAJOR_VERSION == 3 || GPSD_API_MAJOR_VERSION == 4
1673 if (!gps_poll(&vgl->vgpsd->gpsd)) {
1674#elif GPSD_API_MAJOR_VERSION == 5
1675 if (gps_read(&vgl->vgpsd->gpsd) > -1) {
1676 // Reuse old function to perform operations on the new GPS data
1677 gpsd_raw_hook(vgl->vgpsd, NULL);
1678#else
1679 // Broken compile
1680#endif
c5bc70c3 1681 return TRUE;
bff27ab1 1682 }
c5bc70c3 1683 else {
24953b45 1684 g_warning("Disconnected from gpsd. Trying to reconnect");
c5bc70c3
QT
1685 rt_gpsd_disconnect(vgl);
1686 rt_gpsd_connect(vgl, FALSE);
1687 }
1688 }
1689 return FALSE; /* no further calling */
b87d3952
QT
1690}
1691
1692static gchar *make_track_name(VikTrwLayer *vtl)
1693{
1694 const gchar basename[] = "REALTIME";
1695 const gint bufsize = sizeof(basename) + 5;
1696 gchar *name = g_malloc(bufsize);
1697 strcpy(name, basename);
1698 gint i = 2;
1699
1700 while (vik_trw_layer_get_track(vtl, name) != NULL) {
1701 g_snprintf(name, bufsize, "%s#%d", basename, i);
1702 i++;
1703 }
1704 return(name);
1705
1706}
1707
c5bc70c3
QT
1708static gboolean rt_gpsd_try_connect(gpointer *data)
1709{
1710 VikGpsLayer *vgl = (VikGpsLayer *)data;
728db5b5 1711#if GPSD_API_MAJOR_VERSION == 3
c5bc70c3
QT
1712 struct gps_data_t *gpsd = gps_open(vgl->gpsd_host, vgl->gpsd_port);
1713
1714 if (gpsd == NULL) {
728db5b5 1715#elif GPSD_API_MAJOR_VERSION == 4
a263d172
GB
1716 vgl->vgpsd = g_malloc(sizeof(VglGpsd));
1717
1718 if (gps_open_r(vgl->gpsd_host, vgl->gpsd_port, /*(struct gps_data_t *)*/vgl->vgpsd) != 0) {
bff27ab1
RN
1719#elif GPSD_API_MAJOR_VERSION == 5
1720 vgl->vgpsd = g_malloc(sizeof(VglGpsd));
1721 if (gps_open(vgl->gpsd_host, vgl->gpsd_port, &vgl->vgpsd->gpsd) != 0) {
728db5b5 1722#else
bff27ab1 1723// Delibrately break compilation...
a263d172 1724#endif
24953b45
QT
1725 g_warning("Failed to connect to gpsd at %s (port %s). Will retry in %d seconds",
1726 vgl->gpsd_host, vgl->gpsd_port, vgl->gpsd_retry_interval);
c5bc70c3
QT
1727 return TRUE; /* keep timer running */
1728 }
1729
728db5b5 1730#if GPSD_API_MAJOR_VERSION == 3
a263d172
GB
1731 vgl->vgpsd = realloc(gpsd, sizeof(VglGpsd));
1732#endif
c5bc70c3
QT
1733 vgl->vgpsd->vgl = vgl;
1734
1735 vgl->realtime_fix.dirty = vgl->last_fix.dirty = FALSE;
1736 /* track alt/time graph uses VIK_DEFAULT_ALTITUDE (0.0) as invalid */
1737 vgl->realtime_fix.fix.altitude = vgl->last_fix.fix.altitude = VIK_DEFAULT_ALTITUDE;
1738 vgl->realtime_fix.fix.speed = vgl->last_fix.fix.speed = NAN;
1739
1740 if (vgl->realtime_record) {
1741 VikTrwLayer *vtl = vgl->trw_children[TRW_REALTIME];
1742 vgl->realtime_track = vik_track_new();
1743 vgl->realtime_track->visible = TRUE;
ce4bd1cf 1744 vik_trw_layer_add_track(vtl, make_track_name(vtl), vgl->realtime_track);
c5bc70c3
QT
1745 }
1746
bff27ab1 1747#if GPSD_API_MAJOR_VERSION == 3 || GPSD_API_MAJOR_VERSION == 4
c5bc70c3 1748 gps_set_raw_hook(&vgl->vgpsd->gpsd, gpsd_raw_hook);
bff27ab1
RN
1749#endif
1750
c5bc70c3
QT
1751 vgl->realtime_io_channel = g_io_channel_unix_new(vgl->vgpsd->gpsd.gps_fd);
1752 vgl->realtime_io_watch_id = g_io_add_watch( vgl->realtime_io_channel,
1753 G_IO_IN | G_IO_ERR | G_IO_HUP, gpsd_data_available, vgl);
728db5b5
RN
1754
1755#if GPSD_API_MAJOR_VERSION == 3
bec818c4
GB
1756 gps_query(&vgl->vgpsd->gpsd, "w+x");
1757#endif
bff27ab1 1758#if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
728db5b5
RN
1759 gps_stream(&vgl->vgpsd->gpsd, WATCH_ENABLE, NULL);
1760#endif
1761
c5bc70c3
QT
1762 return FALSE; /* no longer called by timeout */
1763}
1764
1765static gboolean rt_ask_retry(VikGpsLayer *vgl)
1766{
1767 GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER(vgl),
1768 GTK_DIALOG_DESTROY_WITH_PARENT,
1769 GTK_MESSAGE_QUESTION,
1770 GTK_BUTTONS_YES_NO,
1771 "Failed to connect to gpsd at %s (port %s)\n"
1772 "Should Viking keep trying (every %d seconds)?",
1773 vgl->gpsd_host, vgl->gpsd_port,
1774 vgl->gpsd_retry_interval);
1775
1776 gint res = gtk_dialog_run(GTK_DIALOG(dialog));
1777 gtk_widget_destroy(dialog);
1778 return (res == GTK_RESPONSE_YES);
1779}
1780
1781static gboolean rt_gpsd_connect(VikGpsLayer *vgl, gboolean ask_if_failed)
1782{
1783 vgl->realtime_retry_timer = 0;
1784 if (rt_gpsd_try_connect((gpointer *)vgl)) {
1785 if (vgl->gpsd_retry_interval <= 0) {
1786 g_warning("Failed to connect to gpsd but will not retry because retry intervel was set to %d (which is 0 or negative)", vgl->gpsd_retry_interval);
1787 return FALSE;
1788 }
1789 else if (ask_if_failed && !rt_ask_retry(vgl))
1790 return FALSE;
1791 else
1792 vgl->realtime_retry_timer = g_timeout_add_seconds(vgl->gpsd_retry_interval,
1793 (GSourceFunc)rt_gpsd_try_connect, (gpointer *)vgl);
1794 }
1795 return TRUE;
1796}
1797
1798static void rt_gpsd_disconnect(VikGpsLayer *vgl)
1799{
c5bc70c3
QT
1800 if (vgl->realtime_retry_timer) {
1801 g_source_remove(vgl->realtime_retry_timer);
1802 vgl->realtime_retry_timer = 0;
1803 }
bff27ab1
RN
1804 if (vgl->realtime_io_watch_id) {
1805 g_source_remove(vgl->realtime_io_watch_id);
1806 vgl->realtime_io_watch_id = 0;
1807 }
c5bc70c3
QT
1808 if (vgl->realtime_io_channel) {
1809 GError *error = NULL;
1810 g_io_channel_shutdown (vgl->realtime_io_channel, FALSE, &error);
1811 vgl->realtime_io_channel = NULL;
1812 }
1813 if (vgl->vgpsd) {
bff27ab1
RN
1814#if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
1815 gps_stream(&vgl->vgpsd->gpsd, WATCH_DISABLE, NULL);
1816#endif
c5bc70c3 1817 gps_close(&vgl->vgpsd->gpsd);
728db5b5 1818#if GPSD_API_MAJOR_VERSION == 3
a263d172 1819 free(vgl->vgpsd);
bff27ab1 1820#elif GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
728db5b5 1821 g_free(vgl->vgpsd);
a263d172 1822#endif
c5bc70c3
QT
1823 vgl->vgpsd = NULL;
1824 }
1825
1826 if (vgl->realtime_record && vgl->realtime_track) {
c5bc70c3 1827 if ((vgl->realtime_track->trackpoints == NULL) || (vgl->realtime_track->trackpoints->next == NULL))
ce4bd1cf 1828 vik_trw_layer_delete_track(vgl->trw_children[TRW_REALTIME], vgl->realtime_track);
c5bc70c3
QT
1829 vgl->realtime_track = NULL;
1830 }
1831}
1832
b87d3952
QT
1833static void gps_start_stop_tracking_cb( gpointer layer_and_vlp[2])
1834{
1835 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1836 vgl->realtime_tracking = (vgl->realtime_tracking == FALSE);
1837
a2817d3c
QT
1838 /* Make sure we are still in the boat with libgps */
1839 g_assert((VIK_GPS_MODE_2D == MODE_2D) && (VIK_GPS_MODE_3D == MODE_3D));
1840
b87d3952 1841 if (vgl->realtime_tracking) {
c5bc70c3
QT
1842 vgl->first_realtime_trackpoint = TRUE;
1843 if (!rt_gpsd_connect(vgl, TRUE)) {
1844 vgl->first_realtime_trackpoint = FALSE;
b87d3952 1845 vgl->realtime_tracking = FALSE;
8b5838b2 1846 vgl->trkpt = NULL;
b87d3952 1847 }
b87d3952
QT
1848 }
1849 else { /* stop realtime tracking */
c5bc70c3 1850 vgl->first_realtime_trackpoint = FALSE;
8b5838b2 1851 vgl->trkpt = NULL;
c5bc70c3 1852 rt_gpsd_disconnect(vgl);
b87d3952
QT
1853 }
1854}
001a86db 1855#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */