2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 * Copyright (C) 2006-2008, Quy Tonthat <qtonthat@gmail.com>
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.
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.
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
32 #include "icons/icons.h"
41 #include <glib/gstdio.h>
42 #include <glib/gprintf.h>
43 #include <glib/gi18n.h>
44 #ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
49 static VikGpsLayer *vik_gps_layer_create (VikViewport *vp);
50 static void vik_gps_layer_realize ( VikGpsLayer *val, VikTreeview *vt, GtkTreeIter *layer_iter );
51 static void vik_gps_layer_free ( VikGpsLayer *val );
52 static void vik_gps_layer_draw ( VikGpsLayer *val, VikViewport *vp );
53 static VikGpsLayer *vik_gps_layer_new ( VikViewport *vp );
55 static void gps_layer_marshall( VikGpsLayer *val, guint8 **data, gint *len );
56 static VikGpsLayer *gps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
57 static gboolean gps_layer_set_param ( VikGpsLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
58 static VikLayerParamData gps_layer_get_param ( VikGpsLayer *vgl, guint16 id, gboolean is_file_operation );
60 static const gchar* gps_layer_tooltip ( VikGpsLayer *vgl );
62 static void gps_layer_change_coord_mode ( VikGpsLayer *val, VikCoordMode mode );
63 static void gps_layer_add_menu_items( VikGpsLayer *vtl, GtkMenu *menu, gpointer vlp );
65 static void gps_upload_cb( gpointer layer_and_vlp[2] );
66 static void gps_download_cb( gpointer layer_and_vlp[2] );
67 static void gps_empty_upload_cb( gpointer layer_and_vlp[2] );
68 static void gps_empty_download_cb( gpointer layer_and_vlp[2] );
69 static void gps_empty_all_cb( gpointer layer_and_vlp[2] );
70 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
71 static void gps_empty_realtime_cb( gpointer layer_and_vlp[2] );
72 static void gps_start_stop_tracking_cb( gpointer layer_and_vlp[2] );
73 static void realtime_tracking_draw(VikGpsLayer *vgl, VikViewport *vp);
74 static void rt_gpsd_disconnect(VikGpsLayer *vgl);
75 static gboolean rt_gpsd_connect(VikGpsLayer *vgl, gboolean ask_if_failed);
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
80 typedef enum {GARMIN_P = 0, MAGELLAN_P, DELORME_P, NAVILINK_P, OLD_NUM_PROTOCOLS} vik_gps_proto;
81 static gchar * protocols_args[] = {"garmin", "magellan", "delbin", "navilink", NULL};
83 static gchar * params_ports[] = {"com1", "usb:", NULL};
85 static gchar * params_ports[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyUSB0", "/dev/ttyUSB1", "usb:", NULL};
87 /* NUM_PORTS not actually used */
88 /* #define NUM_PORTS (sizeof(params_ports)/sizeof(params_ports[0]) - 1) */
89 /* Compatibility with previous versions */
91 static gchar * old_params_ports[] = {"com1", "usb:", NULL};
93 static gchar * old_params_ports[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyUSB0", "/dev/ttyUSB1", "usb:", NULL};
95 #define OLD_NUM_PORTS (sizeof(old_params_ports)/sizeof(old_params_ports[0]) - 1)
99 vik_gps_dir direction;
109 GtkWidget *status_label;
110 GtkWidget *gps_label;
111 GtkWidget *ver_label;
114 GtkWidget *trk_label;
115 GtkWidget *rte_label;
116 GtkWidget *progress_label;
117 vik_gps_xfer_type progress_type;
119 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
120 gboolean realtime_tracking;
123 static void gps_session_delete(GpsSession *sess);
125 static gchar *params_groups[] = {
127 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
128 N_("Realtime Tracking Mode"),
132 enum {GROUP_DATA_MODE, GROUP_REALTIME_MODE};
135 static VikLayerParamData gps_protocol_default ( void )
137 VikLayerParamData data;
138 data.s = g_strdup ( "garmin" );
142 static VikLayerParamData gps_port_default ( void )
144 VikLayerParamData data;
145 data.s = g_strdup ( "usb:" );
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) {
151 g_free ( (gchar *)data.s );
152 data.s = g_strdup ("/dev/ttyUSB1");
154 if (g_access ("/dev/ttyUSB0", R_OK) == 0) {
156 g_free ( (gchar *)data.s );
157 data.s = g_strdup ("/dev/ttyUSB0");
163 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
164 static gchar *params_vehicle_position[] = {
165 N_("Keep vehicle at center"),
166 N_("Keep vehicle on screen"),
171 VEHICLE_POSITION_CENTERED = 0,
172 VEHICLE_POSITION_ON_SCREEN,
173 VEHICLE_POSITION_NONE,
176 static VikLayerParamData moving_map_method_default ( void ) { return VIK_LPD_UINT ( VEHICLE_POSITION_ON_SCREEN ); }
178 static VikLayerParamData gpsd_host_default ( void )
180 VikLayerParamData data;
181 data.s = g_strdup ( "localhost" );
185 static VikLayerParamData gpsd_port_default ( void )
187 VikLayerParamData data;
188 data.s = g_strdup ( DEFAULT_GPSD_PORT );
192 static VikLayerParamData gpsd_retry_interval_default ( void )
194 VikLayerParamData data;
195 data.s = g_strdup ( "10" );
201 static VikLayerParam gps_layer_params[] = {
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()?
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 },
213 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
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 },
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 },
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 },
221 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
224 PARAM_PROTOCOL=0, PARAM_PORT,
225 PARAM_DOWNLOAD_TRACKS, PARAM_UPLOAD_TRACKS,
226 PARAM_DOWNLOAD_ROUTES, PARAM_UPLOAD_ROUTES,
227 PARAM_DOWNLOAD_WAYPOINTS, PARAM_UPLOAD_WAYPOINTS,
228 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
230 PARAM_REALTIME_CENTER_START,
231 PARAM_VEHICLE_POSITION,
232 PARAM_REALTIME_UPDATE_STATUSBAR,
235 PARAM_GPSD_RETRY_INTERVAL,
236 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
239 VikLayerInterface vik_gps_layer_interface = {
251 sizeof(params_groups)/sizeof(params_groups[0]),
255 (VikLayerFuncCreate) vik_gps_layer_create,
256 (VikLayerFuncRealize) vik_gps_layer_realize,
257 (VikLayerFuncPostRead) NULL,
258 (VikLayerFuncFree) vik_gps_layer_free,
260 (VikLayerFuncProperties) NULL,
261 (VikLayerFuncDraw) vik_gps_layer_draw,
262 (VikLayerFuncChangeCoordMode) gps_layer_change_coord_mode,
264 (VikLayerFuncSetMenuItemsSelection) NULL,
265 (VikLayerFuncGetMenuItemsSelection) NULL,
267 (VikLayerFuncAddMenuItems) gps_layer_add_menu_items,
268 (VikLayerFuncSublayerAddMenuItems) NULL,
270 (VikLayerFuncSublayerRenameRequest) NULL,
271 (VikLayerFuncSublayerToggleVisible) NULL,
272 (VikLayerFuncSublayerTooltip) NULL,
273 (VikLayerFuncLayerTooltip) gps_layer_tooltip,
274 (VikLayerFuncLayerSelected) NULL,
276 (VikLayerFuncMarshall) gps_layer_marshall,
277 (VikLayerFuncUnmarshall) gps_layer_unmarshall,
279 (VikLayerFuncSetParam) gps_layer_set_param,
280 (VikLayerFuncGetParam) gps_layer_get_param,
281 (VikLayerFuncChangeParam) NULL,
283 (VikLayerFuncReadFileData) NULL,
284 (VikLayerFuncWriteFileData) NULL,
286 (VikLayerFuncDeleteItem) NULL,
287 (VikLayerFuncCutItem) NULL,
288 (VikLayerFuncCopyItem) NULL,
289 (VikLayerFuncPasteItem) NULL,
290 (VikLayerFuncFreeCopiedItem) NULL,
291 (VikLayerFuncDragDropRequest) NULL,
293 (VikLayerFuncSelectClick) NULL,
294 (VikLayerFuncSelectMove) NULL,
295 (VikLayerFuncSelectRelease) NULL,
296 (VikLayerFuncSelectedViewportMenu) NULL,
299 enum {TRW_DOWNLOAD=0, TRW_UPLOAD,
300 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
304 static gchar * trw_names[] = {
305 N_("GPS Download"), N_("GPS Upload"),
306 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
307 N_("GPS Realtime Tracking"),
311 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
313 struct gps_data_t gpsd;
318 struct gps_fix_t fix;
319 gint satellites_used;
320 gboolean dirty; /* needs to be saved */
322 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
324 struct _VikGpsLayer {
326 VikTrwLayer * trw_children[NUM_TRW];
327 GList * children; /* used only for writing file */
328 int cur_read_child; /* used only for reading file */
329 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
331 gboolean realtime_tracking; /* set/reset only by the callback */
332 gboolean first_realtime_trackpoint;
336 VikTrack *realtime_track;
338 GIOChannel *realtime_io_channel;
339 guint realtime_io_watch_id;
340 guint realtime_retry_timer;
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;
350 gint gpsd_retry_interval;
351 gboolean realtime_record;
352 gboolean realtime_jump_to_start;
353 guint vehicle_position;
354 gboolean realtime_update_statusbar;
355 VikTrackpoint *trkpt;
356 VikTrackpoint *trkpt_prev;
357 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
360 gboolean download_tracks;
361 gboolean download_routes;
362 gboolean download_waypoints;
363 gboolean upload_tracks;
364 gboolean upload_routes;
365 gboolean upload_waypoints;
369 * Overwrite the static setup with dynamically generated GPS Babel device list
371 static void gps_layer_inst_init ( VikGpsLayer *self )
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));
377 GList *gl = g_list_first ( a_babel_device_list );
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 );
384 new_protocols[new_proto] = NULL;
386 vik_gps_layer_interface.params[PARAM_PROTOCOL].widget_data = new_protocols;
389 GType vik_gps_layer_get_type ()
391 static GType val_type = 0;
395 static const GTypeInfo val_info =
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),
405 (GInstanceInitFunc) gps_layer_inst_init,
407 val_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGpsLayer", &val_info, 0 );
413 static VikGpsLayer *vik_gps_layer_create (VikViewport *vp)
417 VikGpsLayer *rv = vik_gps_layer_new (vp);
418 vik_layer_rename ( VIK_LAYER(rv), vik_gps_layer_interface.name );
420 for (i = 0; i < NUM_TRW; i++) {
421 rv->trw_children[i] = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vp, FALSE ));
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));
427 static const gchar* gps_layer_tooltip ( VikGpsLayer *vgl )
429 return vgl->protocol;
433 static void gps_layer_marshall( VikGpsLayer *vgl, guint8 **data, gint *datalen )
435 VikLayer *child_layer;
438 GByteArray* b = g_byte_array_new ();
442 #define alm_append(obj, sz) \
444 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
445 g_byte_array_append ( b, (guint8 *)(obj), len );
447 vik_layer_marshall_params(VIK_LAYER(vgl), &ld, &ll);
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);
461 g_byte_array_free(b, FALSE);
466 static VikGpsLayer *gps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
468 #define alm_size (*(gint *)data)
470 len -= sizeof(gint) + alm_size; \
471 data += sizeof(gint) + alm_size;
473 VikGpsLayer *rv = vik_gps_layer_new(vvp);
474 VikLayer *child_layer;
477 vik_layer_unmarshall_params ( VIK_LAYER(rv), data+sizeof(gint), alm_size, vvp );
481 while (len>0 && i < NUM_TRW) {
482 child_layer = vik_layer_unmarshall ( data + sizeof(gint), alm_size, vvp );
484 rv->trw_children[i++] = (VikTrwLayer *)child_layer;
485 // NB no need to attach signal update handler here
486 // as this will always be performed later on in vik_gps_layer_realize()
490 // g_print("gps_layer_unmarshall ended with len=%d\n", len);
497 static gboolean gps_layer_set_param ( VikGpsLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
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]) &&
509 index < OLD_NUM_PROTOCOLS)
510 // It is a single digit: activate compatibility
511 vgl->protocol = g_strdup(protocols_args[index]);
513 vgl->protocol = g_strdup(data.s);
514 g_debug("%s: %s", __FUNCTION__, vgl->protocol);
517 g_warning(_("Unknown GPS Protocol"));
521 g_free(vgl->serial_port);
522 // Backwards Compatibility: previous versions <v0.9.91 stored serial_port as an array index
523 int index = data.s[0] - '0';
524 if (data.s[0] != '\0' &&
525 g_ascii_isdigit (data.s[0]) &&
527 index < OLD_NUM_PORTS)
528 /* It is a single digit: activate compatibility */
529 vgl->serial_port = g_strdup(old_params_ports[index]);
531 vgl->serial_port = g_strdup(data.s);
532 g_debug("%s: %s", __FUNCTION__, vgl->serial_port);
535 g_warning(_("Unknown serial port device"));
537 case PARAM_DOWNLOAD_TRACKS:
538 vgl->download_tracks = data.b;
540 case PARAM_UPLOAD_TRACKS:
541 vgl->upload_tracks = data.b;
543 case PARAM_DOWNLOAD_ROUTES:
544 vgl->download_routes = data.b;
546 case PARAM_UPLOAD_ROUTES:
547 vgl->upload_routes = data.b;
549 case PARAM_DOWNLOAD_WAYPOINTS:
550 vgl->download_waypoints = data.b;
552 case PARAM_UPLOAD_WAYPOINTS:
553 vgl->upload_waypoints = data.b;
555 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
556 case PARAM_GPSD_HOST:
559 g_free(vgl->gpsd_host);
560 vgl->gpsd_host = g_strdup(data.s);
563 case PARAM_GPSD_PORT:
566 g_free(vgl->gpsd_port);
567 vgl->gpsd_port = g_strdup(data.s);
570 case PARAM_GPSD_RETRY_INTERVAL:
571 vgl->gpsd_retry_interval = strtol(data.s, NULL, 10);
573 case PARAM_REALTIME_REC:
574 vgl->realtime_record = data.b;
576 case PARAM_REALTIME_CENTER_START:
577 vgl->realtime_jump_to_start = data.b;
579 case PARAM_VEHICLE_POSITION:
580 vgl->vehicle_position = data.u;
582 case PARAM_REALTIME_UPDATE_STATUSBAR:
583 vgl->realtime_update_statusbar = data.b;
585 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
587 g_warning("gps_layer_set_param(): unknown parameter");
593 static VikLayerParamData gps_layer_get_param ( VikGpsLayer *vgl, guint16 id, gboolean is_file_operation )
595 VikLayerParamData rv;
599 rv.s = vgl->protocol;
600 g_debug("%s: %s", __FUNCTION__, rv.s);
603 rv.s = vgl->serial_port;
604 g_debug("%s: %s", __FUNCTION__, rv.s);
606 case PARAM_DOWNLOAD_TRACKS:
607 rv.b = vgl->download_tracks;
609 case PARAM_UPLOAD_TRACKS:
610 rv.b = vgl->upload_tracks;
612 case PARAM_DOWNLOAD_ROUTES:
613 rv.b = vgl->download_routes;
615 case PARAM_UPLOAD_ROUTES:
616 rv.b = vgl->upload_routes;
618 case PARAM_DOWNLOAD_WAYPOINTS:
619 rv.b = vgl->download_waypoints;
621 case PARAM_UPLOAD_WAYPOINTS:
622 rv.b = vgl->upload_waypoints;
624 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
625 case PARAM_GPSD_HOST:
626 rv.s = vgl->gpsd_host ? vgl->gpsd_host : "";
628 case PARAM_GPSD_PORT:
629 rv.s = vgl->gpsd_port ? vgl->gpsd_port : g_strdup(DEFAULT_GPSD_PORT);
631 case PARAM_GPSD_RETRY_INTERVAL:
632 rv.s = g_strdup_printf("%d", vgl->gpsd_retry_interval);
634 case PARAM_REALTIME_REC:
635 rv.b = vgl->realtime_record;
637 case PARAM_REALTIME_CENTER_START:
638 rv.b = vgl->realtime_jump_to_start;
640 case PARAM_VEHICLE_POSITION:
641 rv.u = vgl->vehicle_position;
643 case PARAM_REALTIME_UPDATE_STATUSBAR:
644 rv.u = vgl->realtime_update_statusbar;
646 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
648 g_warning(_("%s: unknown parameter"), __FUNCTION__);
654 VikGpsLayer *vik_gps_layer_new (VikViewport *vp)
657 VikGpsLayer *vgl = VIK_GPS_LAYER ( g_object_new ( VIK_GPS_LAYER_TYPE, NULL ) );
658 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GPS );
659 for (i = 0; i < NUM_TRW; i++) {
660 vgl->trw_children[i] = NULL;
662 vgl->children = NULL;
663 vgl->cur_read_child = 0;
665 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
666 vgl->first_realtime_trackpoint = FALSE;
668 vgl->trkpt_prev = NULL;
670 vgl->realtime_io_channel = NULL;
671 vgl->realtime_io_watch_id = 0;
672 vgl->realtime_retry_timer = 0;
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;
680 vgl->realtime_track = NULL;
681 #endif // VIK_CONFIG_REALTIME_GPS_TRACKING
683 vik_layer_set_defaults ( VIK_LAYER(vgl), vp );
688 static void vik_gps_layer_draw ( VikGpsLayer *vgl, VikViewport *vp )
692 VikLayer *trigger = VIK_LAYER(vik_viewport_get_trigger( vp ));
694 for (i = 0; i < NUM_TRW; i++) {
695 vl = VIK_LAYER(vgl->trw_children[i]);
697 if ( vik_viewport_get_half_drawn ( vp ) ) {
698 vik_viewport_set_half_drawn ( vp, FALSE );
699 vik_viewport_snapshot_load( vp );
701 vik_viewport_snapshot_save( vp );
704 if (!vik_viewport_get_half_drawn(vp))
705 vik_layer_draw ( vl, vp );
707 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
708 if (vgl->realtime_tracking) {
709 if (VIK_LAYER(vgl) == trigger) {
710 if ( vik_viewport_get_half_drawn ( vp ) ) {
711 vik_viewport_set_half_drawn ( vp, FALSE );
712 vik_viewport_snapshot_load( vp );
714 vik_viewport_snapshot_save( vp );
717 if (!vik_viewport_get_half_drawn(vp))
718 realtime_tracking_draw(vgl, vp);
720 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
723 static void gps_layer_change_coord_mode ( VikGpsLayer *vgl, VikCoordMode mode )
726 for (i = 0; i < NUM_TRW; i++) {
727 vik_layer_change_coord_mode(VIK_LAYER(vgl->trw_children[i]), mode);
731 static void gps_layer_add_menu_items( VikGpsLayer *vgl, GtkMenu *menu, gpointer vlp )
733 static gpointer pass_along[2];
738 item = gtk_menu_item_new();
739 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
740 gtk_widget_show ( item );
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) );
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 );
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) );
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 );
755 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
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) );
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 );
766 item = gtk_menu_item_new();
767 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
768 gtk_widget_show ( item );
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) );
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 );
775 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
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) );
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 );
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) );
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 );
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) );
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 );
797 static void disconnect_layer_signal ( VikLayer *vl, VikGpsLayer *vgl )
799 guint number_handlers = g_signal_handlers_disconnect_matched(vl, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, vgl);
800 if ( number_handlers != 1 ) {
801 g_critical(_("Unexpected number of disconnected handlers: %d"), number_handlers);
805 static void vik_gps_layer_free ( VikGpsLayer *vgl )
808 for (i = 0; i < NUM_TRW; i++) {
809 if (vgl->vl.realized)
810 disconnect_layer_signal(VIK_LAYER(vgl->trw_children[i]), vgl);
811 g_object_unref(vgl->trw_children[i]);
813 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
814 rt_gpsd_disconnect(vgl);
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);
823 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
826 static void vik_gps_layer_realize ( VikGpsLayer *vgl, VikTreeview *vt, GtkTreeIter *layer_iter )
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....
836 for (ix = 0; ix < NUM_TRW; ix++) {
837 VikLayer * trw = VIK_LAYER(vgl->trw_children[ix]);
838 vik_treeview_add_layer ( VIK_LAYER(vgl)->vt, layer_iter, &iter,
839 _(trw_names[ix]), vgl, TRUE,
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 );
844 g_signal_connect_swapped ( G_OBJECT(trw), "update", G_CALLBACK(vik_layer_emit_update_secondary), vgl );
848 const GList *vik_gps_layer_get_children ( VikGpsLayer *vgl )
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]);
856 return vgl->children;
859 VikTrwLayer * vik_gps_layer_get_a_child(VikGpsLayer *vgl)
861 g_assert ((vgl->cur_read_child >= 0) && (vgl->cur_read_child < NUM_TRW));
863 VikTrwLayer * vtl = vgl->trw_children[vgl->cur_read_child];
864 if (++(vgl->cur_read_child) >= NUM_TRW)
865 vgl->cur_read_child = 0;
869 gboolean vik_gps_layer_is_empty ( VikGpsLayer *vgl )
871 if ( vgl->trw_children[0] )
876 static void gps_session_delete(GpsSession *sess)
878 vik_mutex_free(sess->mutex);
879 g_free(sess->cmd_args);
883 static void set_total_count(gint cnt, GpsSession *sess)
887 g_mutex_lock(sess->mutex);
889 const gchar *tmp_str;
890 if (sess->direction == GPS_DOWN)
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;
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;
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;
913 g_snprintf(s, 128, tmp_str, cnt);
914 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
915 gtk_widget_show ( sess->progress_label );
916 sess->total_count = cnt;
918 g_mutex_unlock(sess->mutex);
922 static void set_current_count(gint cnt, GpsSession *sess)
925 const gchar *tmp_str;
928 g_mutex_lock(sess->mutex);
930 if (cnt < sess->total_count) {
931 if (sess->direction == GPS_DOWN)
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;
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;
946 g_snprintf(s, 128, tmp_str, cnt, sess->total_count);
948 if (sess->direction == GPS_DOWN)
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;
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;
963 g_snprintf(s, 128, tmp_str, cnt);
965 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
967 g_mutex_unlock(sess->mutex);
971 static void set_gps_info(const gchar *info, GpsSession *sess)
975 g_mutex_lock(sess->mutex);
977 g_snprintf(s, 256, _("GPS Device: %s"), info);
978 gtk_label_set_text ( GTK_LABEL(sess->gps_label), s );
980 g_mutex_unlock(sess->mutex);
985 * Common processing for GPS Device information
986 * It doesn't matter whether we're uploading or downloading
988 static void process_line_for_gps_info ( const gchar *line, GpsSession *sess )
990 if (strstr(line, "PRDDAT")) {
991 gchar **tokens = g_strsplit(line, " ", 0);
997 while (tokens[n_tokens])
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
1004 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
1006 sscanf(tokens[i], "%x", &ch);
1010 set_gps_info(info, sess);
1015 /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
1016 if (strstr(line, "Unit:")) {
1017 gchar **tokens = g_strsplit(line, "\t", 0);
1019 while (tokens[n_tokens])
1023 set_gps_info(tokens[1], sess);
1029 static void gps_download_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
1033 gdk_threads_enter ();
1034 g_mutex_lock(sess->mutex);
1036 g_mutex_unlock(sess->mutex);
1037 gps_session_delete(sess);
1038 gdk_threads_leave();
1039 g_thread_exit ( NULL );
1041 g_mutex_unlock(sess->mutex);
1042 gdk_threads_leave ();
1045 case BABEL_DIAG_OUTPUT:
1046 line = (gchar *)data;
1048 gdk_threads_enter();
1049 g_mutex_lock(sess->mutex);
1051 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
1053 g_mutex_unlock(sess->mutex);
1054 gdk_threads_leave();
1056 /* tells us the type of items that will follow */
1057 if (strstr(line, "Xfer Wpt")) {
1058 sess->progress_label = sess->wp_label;
1059 sess->progress_type = WPT;
1061 if (strstr(line, "Xfer Trk")) {
1062 sess->progress_label = sess->trk_label;
1063 sess->progress_type = TRK;
1065 if (strstr(line, "Xfer Rte")) {
1066 sess->progress_label = sess->rte_label;
1067 sess->progress_type = RTE;
1070 process_line_for_gps_info ( line, sess );
1072 if (strstr(line, "RECORD")) {
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);
1083 if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
1085 set_current_count(sess->count, sess);
1096 static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
1101 gdk_threads_enter ();
1102 g_mutex_lock(sess->mutex);
1104 g_mutex_unlock(sess->mutex);
1105 gps_session_delete(sess);
1106 gdk_threads_leave();
1107 g_thread_exit ( NULL );
1109 g_mutex_unlock(sess->mutex);
1110 gdk_threads_leave ();
1113 case BABEL_DIAG_OUTPUT:
1114 line = (gchar *)data;
1116 gdk_threads_enter();
1117 g_mutex_lock(sess->mutex);
1119 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
1121 g_mutex_unlock(sess->mutex);
1122 gdk_threads_leave();
1124 process_line_for_gps_info ( line, sess );
1126 if (strstr(line, "RECORD")) {
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); */
1137 if ( strstr(line, "WPTDAT")) {
1138 if (sess->count == 0) {
1139 sess->progress_label = sess->wp_label;
1140 sess->progress_type = WPT;
1141 set_total_count(cnt, sess);
1144 set_current_count(sess->count, sess);
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);
1156 set_current_count(sess->count, sess);
1158 if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
1159 if (sess->count == 0) {
1160 sess->progress_label = sess->trk_label;
1161 sess->progress_type = TRK;
1162 set_total_count(cnt, sess);
1165 set_current_count(sess->count, sess);
1176 static void gps_comm_thread(GpsSession *sess)
1180 if (sess->direction == GPS_DOWN)
1181 result = a_babel_convert_from (sess->vtl, sess->cmd_args, sess->port,
1182 (BabelStatusFunc) gps_download_progress_func, sess, NULL);
1184 result = a_babel_convert_to (sess->vtl, sess->track, sess->cmd_args, sess->port,
1185 (BabelStatusFunc) gps_upload_progress_func, sess);
1189 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Error: couldn't find gpsbabel.") );
1192 g_mutex_lock(sess->mutex);
1194 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Done.") );
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 );
1198 /* Do not change the view if we are following the current GPS position */
1199 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1200 if (!sess->realtime_tracking)
1203 if ( sess->vvp && sess->direction == GPS_DOWN ) {
1204 /* View the data available */
1205 vik_trw_layer_auto_set_view ( sess->vtl, sess->vvp) ;
1206 vik_layer_emit_update ( VIK_LAYER(sess->vtl) ); // NB update from background thread
1212 g_mutex_unlock(sess->mutex);
1215 g_mutex_lock(sess->mutex);
1218 g_mutex_unlock(sess->mutex);
1221 g_mutex_unlock(sess->mutex);
1222 gps_session_delete(sess);
1224 g_thread_exit(NULL);
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)
1241 * Talk to a GPS Device using a thread which updates a dialog with the progress
1243 gint vik_gps_comm ( VikTrwLayer *vtl,
1250 VikLayersPanel *vlp,
1253 gboolean do_waypoints,
1256 GpsSession *sess = g_malloc(sizeof(GpsSession));
1257 char *tracks = NULL;
1258 char *routes = NULL;
1259 char *waypoints = NULL;
1261 sess->mutex = vik_mutex_new();
1262 sess->direction = dir;
1264 sess->track = track;
1265 sess->port = g_strdup(port);
1267 sess->window_title = (dir == GPS_DOWN) ? _("GPS Download") : _("GPS Upload");
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") );
1281 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1282 sess->realtime_tracking = tracking;
1298 sess->cmd_args = g_strdup_printf("-D 9 %s %s %s -%c %s",
1299 tracks, routes, waypoints, (dir == GPS_DOWN) ? 'i' : 'o', protocol);
1303 // Only create dialog if we're going to do some transferring
1304 if ( do_tracks || do_waypoints || do_routes ) {
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 );
1310 sess->status_label = gtk_label_new (_("Status: detecting gpsbabel"));
1311 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->status_label, FALSE, FALSE, 5 );
1312 gtk_widget_show_all(sess->status_label);
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 ("");
1319 sess->rte_label = gtk_label_new ("");
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 );
1326 gtk_widget_show_all(sess->dialog);
1328 sess->progress_label = sess->wp_label;
1329 sess->total_count = -1;
1331 // Starting gps read/write thread
1332 #if GLIB_CHECK_VERSION (2, 32, 0)
1333 g_thread_try_new ( "gps_comm_thread", (GThreadFunc)gps_comm_thread, sess, NULL );
1335 g_thread_create ( (GThreadFunc)gps_comm_thread, sess, FALSE, NULL );
1338 gtk_dialog_set_default_response ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT );
1339 gtk_dialog_run(GTK_DIALOG(sess->dialog));
1341 gtk_widget_destroy(sess->dialog);
1345 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No GPS items selected for transfer.") );
1348 g_mutex_lock(sess->mutex);
1351 sess->ok = FALSE; /* tell thread to stop */
1352 g_mutex_unlock(sess->mutex);
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");
1358 gboolean result = a_babel_convert_from (NULL, (const char*)device_off, (const char*)port, NULL, NULL, NULL);
1360 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not turn off device.") );
1361 g_free ( device_off );
1363 g_mutex_unlock(sess->mutex);
1364 gps_session_delete(sess);
1370 static void gps_upload_cb( gpointer layer_and_vlp[2] )
1372 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1373 VikLayersPanel *vlp = VIK_LAYERS_PANEL(layer_and_vlp[1]);
1374 VikTrwLayer *vtl = vgl->trw_children[TRW_UPLOAD];
1375 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1376 VikViewport *vvp = vik_window_viewport(vw);
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);
1380 static void gps_download_cb( gpointer layer_and_vlp[2] )
1382 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1383 VikTrwLayer *vtl = vgl->trw_children[TRW_DOWNLOAD];
1384 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1385 VikViewport *vvp = vik_window_viewport(vw);
1386 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
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);
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);
1393 static void gps_empty_upload_cb( gpointer layer_and_vlp[2] )
1395 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
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?"),
1401 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
1402 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
1403 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_UPLOAD]);
1406 static void gps_empty_download_cb( gpointer layer_and_vlp[2] )
1408 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
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?"),
1414 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
1415 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
1416 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_DOWNLOAD]);
1419 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1420 static void gps_empty_realtime_cb( gpointer layer_and_vlp[2] )
1422 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
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?"),
1428 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_REALTIME]);
1429 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_REALTIME]);
1433 static void gps_empty_all_cb( gpointer layer_and_vlp[2] )
1435 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
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?"),
1441 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
1442 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
1443 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_UPLOAD]);
1444 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
1445 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
1446 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_DOWNLOAD]);
1447 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1448 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_REALTIME]);
1449 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_REALTIME]);
1453 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1454 static void realtime_tracking_draw(VikGpsLayer *vgl, VikViewport *vp)
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 );
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 &&
1466 vgl->realtime_fix.fix.longitude < lse.lon &&
1467 !isnan (vgl->realtime_fix.fix.track) ) {
1470 gint half_back_x, half_back_y;
1471 gint half_back_bg_x, half_back_bg_y;
1474 gint side1_x, side1_y, side2_x, side2_y;
1475 gint side1bg_x, side1bg_y, side2bg_x, side2bg_y;
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);
1480 vik_viewport_coord_to_screen ( vp, &gps, &x, &y );
1482 gdouble heading_cos = cos(DEG2RAD(vgl->realtime_fix.fix.track));
1483 gdouble heading_sin = sin(DEG2RAD(vgl->realtime_fix.fix.track));
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;
1490 pt_y = half_back_y-24*heading_cos;
1491 pt_x = half_back_x+24*heading_sin;
1492 //ptbg_y = half_back_bg_y-28*heading_cos;
1493 ptbg_x = half_back_bg_x+28*heading_sin;
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;
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;
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} };
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 );
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;
1517 static VikTrackpoint* create_realtime_trackpoint(VikGpsLayer *vgl, gboolean forced)
1522 /* Note that fix.time is a double, but it should not affect the precision
1524 time_t cur_timestamp = vgl->realtime_fix.fix.time;
1525 time_t last_timestamp = vgl->last_fix.fix.time;
1527 if (cur_timestamp < last_timestamp) {
1531 if (vgl->realtime_record && vgl->realtime_fix.dirty) {
1532 gboolean replace = FALSE;
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);
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) &&
1540 ((cur_timestamp - last_timestamp) < 2)) {
1541 g_free(last_tp->data);
1542 vgl->realtime_track->trackpoints = g_list_delete_link(vgl->realtime_track->trackpoints, last_tp);
1546 ((cur_timestamp != last_timestamp) &&
1548 ((heading < last_heading) && (heading < (last_heading - 3))) ||
1549 ((heading > last_heading) && (heading > (last_heading + 3))) ||
1550 ((alt != VIK_DEFAULT_ALTITUDE) && (alt != last_alt)))))) {
1551 /* TODO: check for new segments */
1552 VikTrackpoint *tp = vik_trackpoint_new();
1553 tp->newsegment = FALSE;
1554 tp->has_timestamp = TRUE;
1555 tp->timestamp = vgl->realtime_fix.fix.time;
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;
1563 ll.lat = vgl->realtime_fix.fix.latitude;
1564 ll.lon = vgl->realtime_fix.fix.longitude;
1565 vik_coord_load_from_latlon(&tp->coord,
1566 vik_trw_layer_get_coord_mode(vgl->trw_children[TRW_REALTIME]), &ll);
1568 vik_track_add_trackpoint ( vgl->realtime_track, tp, TRUE ); // Ensure bounds is recalculated
1569 vgl->realtime_fix.dirty = FALSE;
1570 vgl->realtime_fix.satellites_used = 0;
1571 vgl->last_fix = vgl->realtime_fix;
1578 #define VIK_SETTINGS_GPS_STATUSBAR_FORMAT "gps_statusbar_format"
1580 static void update_statusbar ( VikGpsLayer *vgl, VikWindow *vw )
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" );
1590 gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, vgl->trkpt, vgl->trkpt_prev, vgl->realtime_track, vgl->last_fix.fix.climb );
1591 vik_statusbar_set_message ( vik_window_get_statusbar (vw), VIK_STATUSBAR_INFO, msg );
1595 g_free ( statusbar_format_code );
1599 static void gpsd_raw_hook(VglGpsd *vgpsd, gchar *data)
1601 gboolean update_all = FALSE;
1602 VikGpsLayer *vgl = vgpsd->vgl;
1604 if (!vgl->realtime_tracking) {
1605 g_warning("%s: receiving GPS data while not in realtime mode", __PRETTY_FUNCTION__);
1609 if ((vgpsd->gpsd.fix.mode >= MODE_2D) &&
1610 !isnan(vgpsd->gpsd.fix.latitude) &&
1611 !isnan(vgpsd->gpsd.fix.longitude)) {
1613 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1614 VikViewport *vvp = vik_window_viewport(vw);
1615 vgl->realtime_fix.fix = vgpsd->gpsd.fix;
1616 vgl->realtime_fix.satellites_used = vgpsd->gpsd.satellites_used;
1617 vgl->realtime_fix.dirty = TRUE;
1620 VikCoord vehicle_coord;
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);
1627 if ((vgl->vehicle_position == VEHICLE_POSITION_CENTERED) ||
1628 (vgl->realtime_jump_to_start && vgl->first_realtime_trackpoint)) {
1629 vik_viewport_set_center_coord(vvp, &vehicle_coord, FALSE);
1632 else if (vgl->vehicle_position == VEHICLE_POSITION_ON_SCREEN) {
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);
1640 vik_viewport_coord_to_screen(vvp, &vehicle_coord, &vx, &vy);
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);
1654 vgl->first_realtime_trackpoint = FALSE;
1656 vgl->trkpt = create_realtime_trackpoint ( vgl, FALSE );
1659 if ( vgl->realtime_update_statusbar )
1660 update_statusbar ( vgl, vw );
1661 vgl->trkpt_prev = vgl->trkpt;
1664 vik_layer_emit_update ( update_all ? VIK_LAYER(vgl) : VIK_LAYER(vgl->trw_children[TRW_REALTIME]) ); // NB update from background thread
1668 static gboolean gpsd_data_available(GIOChannel *source, GIOCondition condition, gpointer data)
1670 VikGpsLayer *vgl = data;
1671 if (condition == G_IO_IN) {
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);
1684 g_warning("Disconnected from gpsd. Trying to reconnect");
1685 rt_gpsd_disconnect(vgl);
1686 rt_gpsd_connect(vgl, FALSE);
1689 return FALSE; /* no further calling */
1692 static gchar *make_track_name(VikTrwLayer *vtl)
1694 const gchar basename[] = "REALTIME";
1695 const gint bufsize = sizeof(basename) + 5;
1696 gchar *name = g_malloc(bufsize);
1697 strcpy(name, basename);
1700 while (vik_trw_layer_get_track(vtl, name) != NULL) {
1701 g_snprintf(name, bufsize, "%s#%d", basename, i);
1708 static gboolean rt_gpsd_try_connect(gpointer *data)
1710 VikGpsLayer *vgl = (VikGpsLayer *)data;
1711 #if GPSD_API_MAJOR_VERSION == 3
1712 struct gps_data_t *gpsd = gps_open(vgl->gpsd_host, vgl->gpsd_port);
1715 #elif GPSD_API_MAJOR_VERSION == 4
1716 vgl->vgpsd = g_malloc(sizeof(VglGpsd));
1718 if (gps_open_r(vgl->gpsd_host, vgl->gpsd_port, /*(struct gps_data_t *)*/vgl->vgpsd) != 0) {
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) {
1723 // Delibrately break compilation...
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);
1727 return TRUE; /* keep timer running */
1730 #if GPSD_API_MAJOR_VERSION == 3
1731 vgl->vgpsd = realloc(gpsd, sizeof(VglGpsd));
1733 vgl->vgpsd->vgl = vgl;
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;
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;
1744 vik_trw_layer_add_track(vtl, make_track_name(vtl), vgl->realtime_track);
1747 #if GPSD_API_MAJOR_VERSION == 3 || GPSD_API_MAJOR_VERSION == 4
1748 gps_set_raw_hook(&vgl->vgpsd->gpsd, gpsd_raw_hook);
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);
1755 #if GPSD_API_MAJOR_VERSION == 3
1756 gps_query(&vgl->vgpsd->gpsd, "w+x");
1758 #if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
1759 gps_stream(&vgl->vgpsd->gpsd, WATCH_ENABLE, NULL);
1762 return FALSE; /* no longer called by timeout */
1765 static gboolean rt_ask_retry(VikGpsLayer *vgl)
1767 GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER(vgl),
1768 GTK_DIALOG_DESTROY_WITH_PARENT,
1769 GTK_MESSAGE_QUESTION,
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);
1776 gint res = gtk_dialog_run(GTK_DIALOG(dialog));
1777 gtk_widget_destroy(dialog);
1778 return (res == GTK_RESPONSE_YES);
1781 static gboolean rt_gpsd_connect(VikGpsLayer *vgl, gboolean ask_if_failed)
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);
1789 else if (ask_if_failed && !rt_ask_retry(vgl))
1792 vgl->realtime_retry_timer = g_timeout_add_seconds(vgl->gpsd_retry_interval,
1793 (GSourceFunc)rt_gpsd_try_connect, (gpointer *)vgl);
1798 static void rt_gpsd_disconnect(VikGpsLayer *vgl)
1800 if (vgl->realtime_retry_timer) {
1801 g_source_remove(vgl->realtime_retry_timer);
1802 vgl->realtime_retry_timer = 0;
1804 if (vgl->realtime_io_watch_id) {
1805 g_source_remove(vgl->realtime_io_watch_id);
1806 vgl->realtime_io_watch_id = 0;
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;
1814 #if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
1815 gps_stream(&vgl->vgpsd->gpsd, WATCH_DISABLE, NULL);
1817 gps_close(&vgl->vgpsd->gpsd);
1818 #if GPSD_API_MAJOR_VERSION == 3
1820 #elif GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5
1826 if (vgl->realtime_record && vgl->realtime_track) {
1827 if ((vgl->realtime_track->trackpoints == NULL) || (vgl->realtime_track->trackpoints->next == NULL))
1828 vik_trw_layer_delete_track(vgl->trw_children[TRW_REALTIME], vgl->realtime_track);
1829 vgl->realtime_track = NULL;
1833 static void gps_start_stop_tracking_cb( gpointer layer_and_vlp[2])
1835 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1836 vgl->realtime_tracking = (vgl->realtime_tracking == FALSE);
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));
1841 if (vgl->realtime_tracking) {
1842 vgl->first_realtime_trackpoint = TRUE;
1843 if (!rt_gpsd_connect(vgl, TRUE)) {
1844 vgl->first_realtime_trackpoint = FALSE;
1845 vgl->realtime_tracking = FALSE;
1849 else { /* stop realtime tracking */
1850 vgl->first_realtime_trackpoint = FALSE;
1852 rt_gpsd_disconnect(vgl);
1855 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */