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 (VikLayerFuncGetTimestamp) NULL,
266 (VikLayerFuncSetMenuItemsSelection) NULL,
267 (VikLayerFuncGetMenuItemsSelection) NULL,
269 (VikLayerFuncAddMenuItems) gps_layer_add_menu_items,
270 (VikLayerFuncSublayerAddMenuItems) NULL,
272 (VikLayerFuncSublayerRenameRequest) NULL,
273 (VikLayerFuncSublayerToggleVisible) NULL,
274 (VikLayerFuncSublayerTooltip) NULL,
275 (VikLayerFuncLayerTooltip) gps_layer_tooltip,
276 (VikLayerFuncLayerSelected) NULL,
278 (VikLayerFuncMarshall) gps_layer_marshall,
279 (VikLayerFuncUnmarshall) gps_layer_unmarshall,
281 (VikLayerFuncSetParam) gps_layer_set_param,
282 (VikLayerFuncGetParam) gps_layer_get_param,
283 (VikLayerFuncChangeParam) NULL,
285 (VikLayerFuncReadFileData) NULL,
286 (VikLayerFuncWriteFileData) NULL,
288 (VikLayerFuncDeleteItem) NULL,
289 (VikLayerFuncCutItem) NULL,
290 (VikLayerFuncCopyItem) NULL,
291 (VikLayerFuncPasteItem) NULL,
292 (VikLayerFuncFreeCopiedItem) NULL,
293 (VikLayerFuncDragDropRequest) NULL,
295 (VikLayerFuncSelectClick) NULL,
296 (VikLayerFuncSelectMove) NULL,
297 (VikLayerFuncSelectRelease) NULL,
298 (VikLayerFuncSelectedViewportMenu) NULL,
301 enum {TRW_DOWNLOAD=0, TRW_UPLOAD,
302 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
306 static gchar * trw_names[] = {
307 N_("GPS Download"), N_("GPS Upload"),
308 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
309 N_("GPS Realtime Tracking"),
313 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
315 struct gps_data_t gpsd;
320 struct gps_fix_t fix;
321 gint satellites_used;
322 gboolean dirty; /* needs to be saved */
324 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
326 struct _VikGpsLayer {
328 VikTrwLayer * trw_children[NUM_TRW];
329 GList * children; /* used only for writing file */
330 int cur_read_child; /* used only for reading file */
331 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
333 gboolean realtime_tracking; /* set/reset only by the callback */
334 gboolean first_realtime_trackpoint;
338 VikTrack *realtime_track;
340 GIOChannel *realtime_io_channel;
341 guint realtime_io_watch_id;
342 guint realtime_retry_timer;
343 GdkGC *realtime_track_gc;
344 GdkGC *realtime_track_bg_gc;
345 GdkGC *realtime_track_pt_gc;
346 GdkGC *realtime_track_pt1_gc;
347 GdkGC *realtime_track_pt2_gc;
352 gint gpsd_retry_interval;
353 gboolean realtime_record;
354 gboolean realtime_jump_to_start;
355 guint vehicle_position;
356 gboolean realtime_update_statusbar;
357 VikTrackpoint *trkpt;
358 VikTrackpoint *trkpt_prev;
359 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
362 gboolean download_tracks;
363 gboolean download_routes;
364 gboolean download_waypoints;
365 gboolean upload_tracks;
366 gboolean upload_routes;
367 gboolean upload_waypoints;
371 * Overwrite the static setup with dynamically generated GPS Babel device list
373 static void gps_layer_inst_init ( VikGpsLayer *self )
376 // +1 for luck (i.e the NULL terminator)
377 gchar **new_protocols = g_malloc_n(1 + g_list_length(a_babel_device_list), sizeof(gpointer));
379 GList *gl = g_list_first ( a_babel_device_list );
381 // should be using label property but use name for now
382 // thus don't need to mess around converting label to name later on
383 new_protocols[new_proto++] = ((BabelDevice*)gl->data)->name;
384 gl = g_list_next ( gl );
386 new_protocols[new_proto] = NULL;
388 vik_gps_layer_interface.params[PARAM_PROTOCOL].widget_data = new_protocols;
391 GType vik_gps_layer_get_type ()
393 static GType val_type = 0;
397 static const GTypeInfo val_info =
399 sizeof (VikGpsLayerClass),
400 NULL, /* base_init */
401 NULL, /* base_finalize */
402 NULL, /* class init */
403 NULL, /* class_finalize */
404 NULL, /* class_data */
405 sizeof (VikGpsLayer),
407 (GInstanceInitFunc) gps_layer_inst_init,
409 val_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGpsLayer", &val_info, 0 );
415 static VikGpsLayer *vik_gps_layer_create (VikViewport *vp)
419 VikGpsLayer *rv = vik_gps_layer_new (vp);
420 vik_layer_rename ( VIK_LAYER(rv), vik_gps_layer_interface.name );
422 for (i = 0; i < NUM_TRW; i++) {
423 rv->trw_children[i] = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vp, FALSE ));
424 vik_layer_set_menu_items_selection(VIK_LAYER(rv->trw_children[i]), VIK_MENU_ITEM_ALL & ~(VIK_MENU_ITEM_CUT|VIK_MENU_ITEM_DELETE));
429 static const gchar* gps_layer_tooltip ( VikGpsLayer *vgl )
431 return vgl->protocol;
435 static void gps_layer_marshall( VikGpsLayer *vgl, guint8 **data, gint *datalen )
437 VikLayer *child_layer;
440 GByteArray* b = g_byte_array_new ();
444 #define alm_append(obj, sz) \
446 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
447 g_byte_array_append ( b, (guint8 *)(obj), len );
449 vik_layer_marshall_params(VIK_LAYER(vgl), &ld, &ll);
453 for (i = 0; i < NUM_TRW; i++) {
454 child_layer = VIK_LAYER(vgl->trw_children[i]);
455 vik_layer_marshall(child_layer, &ld, &ll);
463 g_byte_array_free(b, FALSE);
468 static VikGpsLayer *gps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
470 #define alm_size (*(gint *)data)
472 len -= sizeof(gint) + alm_size; \
473 data += sizeof(gint) + alm_size;
475 VikGpsLayer *rv = vik_gps_layer_new(vvp);
476 VikLayer *child_layer;
479 vik_layer_unmarshall_params ( VIK_LAYER(rv), data+sizeof(gint), alm_size, vvp );
483 while (len>0 && i < NUM_TRW) {
484 child_layer = vik_layer_unmarshall ( data + sizeof(gint), alm_size, vvp );
486 rv->trw_children[i++] = (VikTrwLayer *)child_layer;
487 // NB no need to attach signal update handler here
488 // as this will always be performed later on in vik_gps_layer_realize()
492 // g_print("gps_layer_unmarshall ended with len=%d\n", len);
499 static gboolean gps_layer_set_param ( VikGpsLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
505 g_free(vgl->protocol);
506 // Backwards Compatibility: previous versions <v1.4 stored protocol as an array index
507 int index = data.s[0] - '0';
508 if (data.s[0] != '\0' &&
509 g_ascii_isdigit (data.s[0]) &&
511 index < OLD_NUM_PROTOCOLS)
512 // It is a single digit: activate compatibility
513 vgl->protocol = g_strdup(protocols_args[index]);
515 vgl->protocol = g_strdup(data.s);
516 g_debug("%s: %s", __FUNCTION__, vgl->protocol);
519 g_warning(_("Unknown GPS Protocol"));
523 g_free(vgl->serial_port);
524 // Backwards Compatibility: previous versions <v0.9.91 stored serial_port as an array index
525 int index = data.s[0] - '0';
526 if (data.s[0] != '\0' &&
527 g_ascii_isdigit (data.s[0]) &&
529 index < OLD_NUM_PORTS)
530 /* It is a single digit: activate compatibility */
531 vgl->serial_port = g_strdup(old_params_ports[index]);
533 vgl->serial_port = g_strdup(data.s);
534 g_debug("%s: %s", __FUNCTION__, vgl->serial_port);
537 g_warning(_("Unknown serial port device"));
539 case PARAM_DOWNLOAD_TRACKS:
540 vgl->download_tracks = data.b;
542 case PARAM_UPLOAD_TRACKS:
543 vgl->upload_tracks = data.b;
545 case PARAM_DOWNLOAD_ROUTES:
546 vgl->download_routes = data.b;
548 case PARAM_UPLOAD_ROUTES:
549 vgl->upload_routes = data.b;
551 case PARAM_DOWNLOAD_WAYPOINTS:
552 vgl->download_waypoints = data.b;
554 case PARAM_UPLOAD_WAYPOINTS:
555 vgl->upload_waypoints = data.b;
557 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
558 case PARAM_GPSD_HOST:
561 g_free(vgl->gpsd_host);
562 vgl->gpsd_host = g_strdup(data.s);
565 case PARAM_GPSD_PORT:
568 g_free(vgl->gpsd_port);
569 vgl->gpsd_port = g_strdup(data.s);
572 case PARAM_GPSD_RETRY_INTERVAL:
573 vgl->gpsd_retry_interval = strtol(data.s, NULL, 10);
575 case PARAM_REALTIME_REC:
576 vgl->realtime_record = data.b;
578 case PARAM_REALTIME_CENTER_START:
579 vgl->realtime_jump_to_start = data.b;
581 case PARAM_VEHICLE_POSITION:
582 vgl->vehicle_position = data.u;
584 case PARAM_REALTIME_UPDATE_STATUSBAR:
585 vgl->realtime_update_statusbar = data.b;
587 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
589 g_warning("gps_layer_set_param(): unknown parameter");
595 static VikLayerParamData gps_layer_get_param ( VikGpsLayer *vgl, guint16 id, gboolean is_file_operation )
597 VikLayerParamData rv;
601 rv.s = vgl->protocol;
602 g_debug("%s: %s", __FUNCTION__, rv.s);
605 rv.s = vgl->serial_port;
606 g_debug("%s: %s", __FUNCTION__, rv.s);
608 case PARAM_DOWNLOAD_TRACKS:
609 rv.b = vgl->download_tracks;
611 case PARAM_UPLOAD_TRACKS:
612 rv.b = vgl->upload_tracks;
614 case PARAM_DOWNLOAD_ROUTES:
615 rv.b = vgl->download_routes;
617 case PARAM_UPLOAD_ROUTES:
618 rv.b = vgl->upload_routes;
620 case PARAM_DOWNLOAD_WAYPOINTS:
621 rv.b = vgl->download_waypoints;
623 case PARAM_UPLOAD_WAYPOINTS:
624 rv.b = vgl->upload_waypoints;
626 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
627 case PARAM_GPSD_HOST:
628 rv.s = vgl->gpsd_host ? vgl->gpsd_host : "";
630 case PARAM_GPSD_PORT:
631 rv.s = vgl->gpsd_port ? vgl->gpsd_port : g_strdup(DEFAULT_GPSD_PORT);
633 case PARAM_GPSD_RETRY_INTERVAL:
634 rv.s = g_strdup_printf("%d", vgl->gpsd_retry_interval);
636 case PARAM_REALTIME_REC:
637 rv.b = vgl->realtime_record;
639 case PARAM_REALTIME_CENTER_START:
640 rv.b = vgl->realtime_jump_to_start;
642 case PARAM_VEHICLE_POSITION:
643 rv.u = vgl->vehicle_position;
645 case PARAM_REALTIME_UPDATE_STATUSBAR:
646 rv.u = vgl->realtime_update_statusbar;
648 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
650 g_warning(_("%s: unknown parameter"), __FUNCTION__);
656 VikGpsLayer *vik_gps_layer_new (VikViewport *vp)
659 VikGpsLayer *vgl = VIK_GPS_LAYER ( g_object_new ( VIK_GPS_LAYER_TYPE, NULL ) );
660 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GPS );
661 for (i = 0; i < NUM_TRW; i++) {
662 vgl->trw_children[i] = NULL;
664 vgl->children = NULL;
665 vgl->cur_read_child = 0;
667 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
668 vgl->first_realtime_trackpoint = FALSE;
670 vgl->trkpt_prev = NULL;
672 vgl->realtime_io_channel = NULL;
673 vgl->realtime_io_watch_id = 0;
674 vgl->realtime_retry_timer = 0;
676 vgl->realtime_track_gc = vik_viewport_new_gc ( vp, "#203070", 2 );
677 vgl->realtime_track_bg_gc = vik_viewport_new_gc ( vp, "grey", 2 );
678 vgl->realtime_track_pt1_gc = vik_viewport_new_gc ( vp, "red", 2 );
679 vgl->realtime_track_pt2_gc = vik_viewport_new_gc ( vp, "green", 2 );
680 vgl->realtime_track_pt_gc = vgl->realtime_track_pt1_gc;
682 vgl->realtime_track = NULL;
683 #endif // VIK_CONFIG_REALTIME_GPS_TRACKING
685 vik_layer_set_defaults ( VIK_LAYER(vgl), vp );
690 static void vik_gps_layer_draw ( VikGpsLayer *vgl, VikViewport *vp )
694 VikLayer *trigger = VIK_LAYER(vik_viewport_get_trigger( vp ));
696 for (i = 0; i < NUM_TRW; i++) {
697 vl = VIK_LAYER(vgl->trw_children[i]);
699 if ( vik_viewport_get_half_drawn ( vp ) ) {
700 vik_viewport_set_half_drawn ( vp, FALSE );
701 vik_viewport_snapshot_load( vp );
703 vik_viewport_snapshot_save( vp );
706 if (!vik_viewport_get_half_drawn(vp))
707 vik_layer_draw ( vl, vp );
709 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
710 if (vgl->realtime_tracking) {
711 if (VIK_LAYER(vgl) == trigger) {
712 if ( vik_viewport_get_half_drawn ( vp ) ) {
713 vik_viewport_set_half_drawn ( vp, FALSE );
714 vik_viewport_snapshot_load( vp );
716 vik_viewport_snapshot_save( vp );
719 if (!vik_viewport_get_half_drawn(vp))
720 realtime_tracking_draw(vgl, vp);
722 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
725 static void gps_layer_change_coord_mode ( VikGpsLayer *vgl, VikCoordMode mode )
728 for (i = 0; i < NUM_TRW; i++) {
729 vik_layer_change_coord_mode(VIK_LAYER(vgl->trw_children[i]), mode);
733 static void gps_layer_add_menu_items( VikGpsLayer *vgl, GtkMenu *menu, gpointer vlp )
735 static gpointer pass_along[2];
740 item = gtk_menu_item_new();
741 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
742 gtk_widget_show ( item );
745 item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS") );
746 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
747 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_upload_cb), pass_along );
748 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
749 gtk_widget_show ( item );
751 item = gtk_image_menu_item_new_with_mnemonic ( _("Download from _GPS") );
752 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU) );
753 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_download_cb), pass_along );
754 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
755 gtk_widget_show ( item );
757 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
758 item = gtk_image_menu_item_new_with_mnemonic ( vgl->realtime_tracking ?
759 "_Stop Realtime Tracking" :
760 "_Start Realtime Tracking" );
761 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, vgl->realtime_tracking ?
762 gtk_image_new_from_stock (GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_MENU) :
763 gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU) );
764 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_start_stop_tracking_cb), pass_along );
765 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
766 gtk_widget_show ( item );
768 item = gtk_menu_item_new();
769 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
770 gtk_widget_show ( item );
772 item = gtk_image_menu_item_new_with_mnemonic ( _("Empty _Realtime") );
773 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
774 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_realtime_cb), pass_along );
775 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
776 gtk_widget_show ( item );
777 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
779 item = gtk_image_menu_item_new_with_mnemonic ( _("E_mpty Upload") );
780 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
781 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_upload_cb), pass_along );
782 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
783 gtk_widget_show ( item );
785 item = gtk_image_menu_item_new_with_mnemonic ( _("_Empty Download") );
786 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
787 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_download_cb), pass_along );
788 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
789 gtk_widget_show ( item );
791 item = gtk_image_menu_item_new_with_mnemonic ( _("Empty _All") );
792 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
793 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_all_cb), pass_along );
794 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
795 gtk_widget_show ( item );
799 static void disconnect_layer_signal ( VikLayer *vl, VikGpsLayer *vgl )
801 guint number_handlers = g_signal_handlers_disconnect_matched(vl, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, vgl);
802 if ( number_handlers != 1 ) {
803 g_critical(_("Unexpected number of disconnected handlers: %d"), number_handlers);
807 static void vik_gps_layer_free ( VikGpsLayer *vgl )
810 for (i = 0; i < NUM_TRW; i++) {
811 if (vgl->vl.realized)
812 disconnect_layer_signal(VIK_LAYER(vgl->trw_children[i]), vgl);
813 g_object_unref(vgl->trw_children[i]);
815 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
816 rt_gpsd_disconnect(vgl);
817 if (vgl->realtime_track_gc != NULL)
818 g_object_unref(vgl->realtime_track_gc);
819 if (vgl->realtime_track_bg_gc != NULL)
820 g_object_unref(vgl->realtime_track_bg_gc);
821 if (vgl->realtime_track_pt1_gc != NULL)
822 g_object_unref(vgl->realtime_track_pt1_gc);
823 if (vgl->realtime_track_pt2_gc != NULL)
824 g_object_unref(vgl->realtime_track_pt2_gc);
825 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
828 static void vik_gps_layer_realize ( VikGpsLayer *vgl, VikTreeview *vt, GtkTreeIter *layer_iter )
833 // TODO set to garmin by default
834 //if (a_babel_device_list)
835 // device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
836 // Need to access uibuild widgets somehow....
838 for (ix = 0; ix < NUM_TRW; ix++) {
839 VikLayer * trw = VIK_LAYER(vgl->trw_children[ix]);
840 vik_treeview_add_layer ( VIK_LAYER(vgl)->vt, layer_iter, &iter,
841 _(trw_names[ix]), vgl, TRUE,
842 trw, trw->type, trw->type, vik_layer_get_timestamp(trw) );
843 if ( ! trw->visible )
844 vik_treeview_item_set_visible ( VIK_LAYER(vgl)->vt, &iter, FALSE );
845 vik_layer_realize ( trw, VIK_LAYER(vgl)->vt, &iter );
846 g_signal_connect_swapped ( G_OBJECT(trw), "update", G_CALLBACK(vik_layer_emit_update_secondary), vgl );
850 const GList *vik_gps_layer_get_children ( VikGpsLayer *vgl )
854 if (vgl->children == NULL) {
855 for (i = NUM_TRW - 1; i >= 0; i--)
856 vgl->children = g_list_prepend(vgl->children, vgl->trw_children[i]);
858 return vgl->children;
861 VikTrwLayer * vik_gps_layer_get_a_child(VikGpsLayer *vgl)
863 g_assert ((vgl->cur_read_child >= 0) && (vgl->cur_read_child < NUM_TRW));
865 VikTrwLayer * vtl = vgl->trw_children[vgl->cur_read_child];
866 if (++(vgl->cur_read_child) >= NUM_TRW)
867 vgl->cur_read_child = 0;
871 gboolean vik_gps_layer_is_empty ( VikGpsLayer *vgl )
873 if ( vgl->trw_children[0] )
878 static void gps_session_delete(GpsSession *sess)
880 vik_mutex_free(sess->mutex);
881 g_free(sess->babelargs);
885 static void set_total_count(gint cnt, GpsSession *sess)
889 g_mutex_lock(sess->mutex);
891 const gchar *tmp_str;
892 if (sess->direction == GPS_DOWN)
894 switch (sess->progress_type) {
895 case WPT: tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt); sess->total_count = cnt; break;
896 case TRK: tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt); sess->total_count = cnt; break;
899 // 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
900 gint mycnt = (cnt / 2) + 1;
901 tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", mycnt); break;
902 sess->total_count = mycnt;
908 switch (sess->progress_type) {
909 case WPT: tmp_str = ngettext("Uploading %d waypoint...", "Uploading %d waypoints...", cnt); break;
910 case TRK: tmp_str = ngettext("Uploading %d trackpoint...", "Uploading %d trackpoints...", cnt); break;
911 default: tmp_str = ngettext("Uploading %d routepoint...", "Uploading %d routepoints...", cnt); break;
915 g_snprintf(s, 128, tmp_str, cnt);
916 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
917 gtk_widget_show ( sess->progress_label );
918 sess->total_count = cnt;
920 g_mutex_unlock(sess->mutex);
924 static void set_current_count(gint cnt, GpsSession *sess)
927 const gchar *tmp_str;
930 g_mutex_lock(sess->mutex);
932 if (cnt < sess->total_count) {
933 if (sess->direction == GPS_DOWN)
935 switch (sess->progress_type) {
936 case WPT: tmp_str = ngettext("Downloaded %d out of %d waypoint...", "Downloaded %d out of %d waypoints...", sess->total_count); break;
937 case TRK: tmp_str = ngettext("Downloaded %d out of %d trackpoint...", "Downloaded %d out of %d trackpoints...", sess->total_count); break;
938 default: tmp_str = ngettext("Downloaded %d out of %d routepoint...", "Downloaded %d out of %d routepoints...", sess->total_count); break;
942 switch (sess->progress_type) {
943 case WPT: tmp_str = ngettext("Uploaded %d out of %d waypoint...", "Uploaded %d out of %d waypoints...", sess->total_count); break;
944 case TRK: tmp_str = ngettext("Uploaded %d out of %d trackpoint...", "Uploaded %d out of %d trackpoints...", sess->total_count); break;
945 default: tmp_str = ngettext("Uploaded %d out of %d routepoint...", "Uploaded %d out of %d routepoints...", sess->total_count); break;
948 g_snprintf(s, 128, tmp_str, cnt, sess->total_count);
950 if (sess->direction == GPS_DOWN)
952 switch (sess->progress_type) {
953 case WPT: tmp_str = ngettext("Downloaded %d waypoint", "Downloaded %d waypoints", cnt); break;
954 case TRK: tmp_str = ngettext("Downloaded %d trackpoint", "Downloaded %d trackpoints", cnt); break;
955 default: tmp_str = ngettext("Downloaded %d routepoint", "Downloaded %d routepoints", cnt); break;
959 switch (sess->progress_type) {
960 case WPT: tmp_str = ngettext("Uploaded %d waypoint", "Uploaded %d waypoints", cnt); break;
961 case TRK: tmp_str = ngettext("Uploaded %d trackpoint", "Uploaded %d trackpoints", cnt); break;
962 default: tmp_str = ngettext("Uploaded %d routepoint", "Uploaded %d routepoints", cnt); break;
965 g_snprintf(s, 128, tmp_str, cnt);
967 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
969 g_mutex_unlock(sess->mutex);
973 static void set_gps_info(const gchar *info, GpsSession *sess)
977 g_mutex_lock(sess->mutex);
979 g_snprintf(s, 256, _("GPS Device: %s"), info);
980 gtk_label_set_text ( GTK_LABEL(sess->gps_label), s );
982 g_mutex_unlock(sess->mutex);
987 * Common processing for GPS Device information
988 * It doesn't matter whether we're uploading or downloading
990 static void process_line_for_gps_info ( const gchar *line, GpsSession *sess )
992 if (strstr(line, "PRDDAT")) {
993 gchar **tokens = g_strsplit(line, " ", 0);
999 while (tokens[n_tokens])
1002 // I'm not entirely clear what information this is trying to get...
1003 // Obviously trying to decipher some kind of text/naming scheme
1004 // Anyway this will be superceded if there is 'Unit:' information
1006 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
1008 sscanf(tokens[i], "%x", &ch);
1012 set_gps_info(info, sess);
1017 /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
1018 if (strstr(line, "Unit:")) {
1019 gchar **tokens = g_strsplit(line, "\t", 0);
1021 while (tokens[n_tokens])
1025 set_gps_info(tokens[1], sess);
1031 static void gps_download_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
1035 gdk_threads_enter ();
1036 g_mutex_lock(sess->mutex);
1038 g_mutex_unlock(sess->mutex);
1039 gps_session_delete(sess);
1040 gdk_threads_leave();
1041 g_thread_exit ( NULL );
1043 g_mutex_unlock(sess->mutex);
1044 gdk_threads_leave ();
1047 case BABEL_DIAG_OUTPUT:
1048 line = (gchar *)data;
1050 gdk_threads_enter();
1051 g_mutex_lock(sess->mutex);
1053 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
1055 g_mutex_unlock(sess->mutex);
1056 gdk_threads_leave();
1058 /* tells us the type of items that will follow */
1059 if (strstr(line, "Xfer Wpt")) {
1060 sess->progress_label = sess->wp_label;
1061 sess->progress_type = WPT;
1063 if (strstr(line, "Xfer Trk")) {
1064 sess->progress_label = sess->trk_label;
1065 sess->progress_type = TRK;
1067 if (strstr(line, "Xfer Rte")) {
1068 sess->progress_label = sess->rte_label;
1069 sess->progress_type = RTE;
1072 process_line_for_gps_info ( line, sess );
1074 if (strstr(line, "RECORD")) {
1077 if (strlen(line) > 20) {
1078 sscanf(line+17, "%x", &lsb);
1079 sscanf(line+20, "%x", &msb);
1080 cnt = lsb + msb * 256;
1081 set_total_count(cnt, sess);
1085 if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
1087 set_current_count(sess->count, sess);
1098 static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
1103 gdk_threads_enter ();
1104 g_mutex_lock(sess->mutex);
1106 g_mutex_unlock(sess->mutex);
1107 gps_session_delete(sess);
1108 gdk_threads_leave();
1109 g_thread_exit ( NULL );
1111 g_mutex_unlock(sess->mutex);
1112 gdk_threads_leave ();
1115 case BABEL_DIAG_OUTPUT:
1116 line = (gchar *)data;
1118 gdk_threads_enter();
1119 g_mutex_lock(sess->mutex);
1121 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Status: Working...") );
1123 g_mutex_unlock(sess->mutex);
1124 gdk_threads_leave();
1126 process_line_for_gps_info ( line, sess );
1128 if (strstr(line, "RECORD")) {
1131 if (strlen(line) > 20) {
1132 sscanf(line+17, "%x", &lsb);
1133 sscanf(line+20, "%x", &msb);
1134 cnt = lsb + msb * 256;
1135 /* set_total_count(cnt, sess); */
1139 if ( strstr(line, "WPTDAT")) {
1140 if (sess->count == 0) {
1141 sess->progress_label = sess->wp_label;
1142 sess->progress_type = WPT;
1143 set_total_count(cnt, sess);
1146 set_current_count(sess->count, sess);
1148 if ( strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
1149 if (sess->count == 0) {
1150 sess->progress_label = sess->rte_label;
1151 sess->progress_type = RTE;
1152 // 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
1153 // Anyway since we're uploading - we should know how many points we're going to put!
1154 cnt = (cnt / 2) + 1;
1155 set_total_count(cnt, sess);
1158 set_current_count(sess->count, sess);
1160 if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
1161 if (sess->count == 0) {
1162 sess->progress_label = sess->trk_label;
1163 sess->progress_type = TRK;
1164 set_total_count(cnt, sess);
1167 set_current_count(sess->count, sess);
1178 static void gps_comm_thread(GpsSession *sess)
1182 if (sess->direction == GPS_DOWN) {
1183 ProcessOptions po = { sess->babelargs, sess->port, NULL, NULL, NULL, NULL };
1184 result = a_babel_convert_from (sess->vtl, &po, (BabelStatusFunc) gps_download_progress_func, sess, NULL);
1187 result = a_babel_convert_to (sess->vtl, sess->track, sess->babelargs, sess->port,
1188 (BabelStatusFunc) gps_upload_progress_func, sess);
1192 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Error: couldn't find gpsbabel.") );
1195 g_mutex_lock(sess->mutex);
1197 gtk_label_set_text ( GTK_LABEL(sess->status_label), _("Done.") );
1198 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT, TRUE );
1199 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_REJECT, FALSE );
1201 /* Do not change the view if we are following the current GPS position */
1202 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1203 if (!sess->realtime_tracking)
1206 if ( sess->vvp && sess->direction == GPS_DOWN ) {
1207 vik_layer_post_read ( VIK_LAYER(sess->vtl), sess->vvp, TRUE );
1208 /* View the data available */
1209 vik_trw_layer_auto_set_view ( sess->vtl, sess->vvp ) ;
1210 vik_layer_emit_update ( VIK_LAYER(sess->vtl) ); // NB update from background thread
1216 g_mutex_unlock(sess->mutex);
1219 g_mutex_lock(sess->mutex);
1222 g_mutex_unlock(sess->mutex);
1225 g_mutex_unlock(sess->mutex);
1226 gps_session_delete(sess);
1228 g_thread_exit(NULL);
1233 * @vtl: The TrackWaypoint layer to operate on
1234 * @track: Operate on a particular track when specified
1235 * @dir: The direction of the transfer
1236 * @protocol: The GPS device communication protocol
1237 * @port: The GPS serial port
1238 * @tracking: If tracking then viewport display update will be skipped
1239 * @vvp: A viewport is required as the display may get updated
1240 * @vlp: A layers panel is needed for uploading as the items maybe modified
1241 * @do_tracks: Whether tracks shoud be processed
1242 * @do_waypoints: Whether waypoints shoud be processed
1243 * @turn_off: Whether we should attempt to turn off the GPS device after the transfer (only some devices support this)
1245 * Talk to a GPS Device using a thread which updates a dialog with the progress
1247 gint vik_gps_comm ( VikTrwLayer *vtl,
1254 VikLayersPanel *vlp,
1257 gboolean do_waypoints,
1260 GpsSession *sess = g_malloc(sizeof(GpsSession));
1261 char *tracks = NULL;
1262 char *routes = NULL;
1263 char *waypoints = NULL;
1265 sess->mutex = vik_mutex_new();
1266 sess->direction = dir;
1268 sess->track = track;
1269 sess->port = g_strdup(port);
1271 sess->window_title = (dir == GPS_DOWN) ? _("GPS Download") : _("GPS Upload");
1274 // This must be done inside the main thread as the uniquify causes screen updates
1275 // (originally performed this nearer the point of upload in the thread)
1276 if ( dir == GPS_UP ) {
1277 // Enforce unique names in the layer upload to the GPS device
1278 // NB this may only be a Garmin device restriction (and may be not every Garmin device either...)
1279 // Thus this maintains the older code in built restriction
1280 if ( ! vik_trw_layer_uniquify ( sess->vtl, vlp ) )
1281 vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(sess->vtl))), VIK_STATUSBAR_INFO,
1282 _("Warning - GPS Upload items may overwrite each other") );
1285 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1286 sess->realtime_tracking = tracking;
1302 sess->babelargs = g_strdup_printf("-D 9 %s %s %s -%c %s",
1303 tracks, routes, waypoints, (dir == GPS_DOWN) ? 'i' : 'o', protocol);
1307 // Only create dialog if we're going to do some transferring
1308 if ( do_tracks || do_waypoints || do_routes ) {
1309 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 );
1310 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog),
1311 GTK_RESPONSE_ACCEPT, FALSE );
1312 gtk_window_set_title ( GTK_WINDOW(sess->dialog), sess->window_title );
1314 sess->status_label = gtk_label_new (_("Status: detecting gpsbabel"));
1315 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->status_label, FALSE, FALSE, 5 );
1316 gtk_widget_show_all(sess->status_label);
1318 sess->gps_label = gtk_label_new (_("GPS device: N/A"));
1319 sess->ver_label = gtk_label_new ("");
1320 sess->id_label = gtk_label_new ("");
1321 sess->wp_label = gtk_label_new ("");
1322 sess->trk_label = gtk_label_new ("");
1323 sess->rte_label = gtk_label_new ("");
1325 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->gps_label, FALSE, FALSE, 5 );
1326 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->wp_label, FALSE, FALSE, 5 );
1327 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->trk_label, FALSE, FALSE, 5 );
1328 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sess->dialog))), sess->rte_label, FALSE, FALSE, 5 );
1330 gtk_widget_show_all(sess->dialog);
1332 sess->progress_label = sess->wp_label;
1333 sess->total_count = -1;
1335 // Starting gps read/write thread
1336 #if GLIB_CHECK_VERSION (2, 32, 0)
1337 g_thread_try_new ( "gps_comm_thread", (GThreadFunc)gps_comm_thread, sess, NULL );
1339 g_thread_create ( (GThreadFunc)gps_comm_thread, sess, FALSE, NULL );
1342 gtk_dialog_set_default_response ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT );
1343 gtk_dialog_run(GTK_DIALOG(sess->dialog));
1345 gtk_widget_destroy(sess->dialog);
1349 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No GPS items selected for transfer.") );
1352 g_mutex_lock(sess->mutex);
1355 sess->ok = FALSE; /* tell thread to stop */
1356 g_mutex_unlock(sess->mutex);
1360 // No need for thread for powering off device (should be quick operation...) - so use babel command directly:
1361 gchar *device_off = g_strdup_printf("-i %s,%s", protocol, "power_off");
1362 ProcessOptions po = { device_off, port, NULL, NULL, NULL, NULL };
1363 gboolean result = a_babel_convert_from (NULL, &po, NULL, NULL, NULL);
1365 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not turn off device.") );
1366 g_free ( device_off );
1368 g_mutex_unlock(sess->mutex);
1369 gps_session_delete(sess);
1375 static void gps_upload_cb( gpointer layer_and_vlp[2] )
1377 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1378 VikLayersPanel *vlp = VIK_LAYERS_PANEL(layer_and_vlp[1]);
1379 VikTrwLayer *vtl = vgl->trw_children[TRW_UPLOAD];
1380 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1381 VikViewport *vvp = vik_window_viewport(vw);
1382 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);
1385 static void gps_download_cb( gpointer layer_and_vlp[2] )
1387 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1388 VikTrwLayer *vtl = vgl->trw_children[TRW_DOWNLOAD];
1389 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1390 VikViewport *vvp = vik_window_viewport(vw);
1391 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1392 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);
1394 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);
1398 static void gps_empty_upload_cb( gpointer layer_and_vlp[2] )
1400 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1401 // Get confirmation from the user
1402 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1403 _("Are you sure you want to delete GPS Upload data?"),
1406 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
1407 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
1408 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_UPLOAD]);
1411 static void gps_empty_download_cb( gpointer layer_and_vlp[2] )
1413 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1414 // Get confirmation from the user
1415 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1416 _("Are you sure you want to delete GPS Download data?"),
1419 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
1420 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
1421 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_DOWNLOAD]);
1424 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1425 static void gps_empty_realtime_cb( gpointer layer_and_vlp[2] )
1427 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1428 // Get confirmation from the user
1429 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1430 _("Are you sure you want to delete GPS Realtime data?"),
1433 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_REALTIME]);
1434 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_REALTIME]);
1438 static void gps_empty_all_cb( gpointer layer_and_vlp[2] )
1440 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1441 // Get confirmation from the user
1442 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_WIDGET(layer_and_vlp[1]),
1443 _("Are you sure you want to delete All GPS data?"),
1446 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
1447 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
1448 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_UPLOAD]);
1449 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
1450 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
1451 vik_trw_layer_delete_all_routes ( vgl-> trw_children[TRW_DOWNLOAD]);
1452 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1453 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_REALTIME]);
1454 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_REALTIME]);
1458 #if defined (VIK_CONFIG_REALTIME_GPS_TRACKING) && defined (GPSD_API_MAJOR_VERSION)
1459 static void realtime_tracking_draw(VikGpsLayer *vgl, VikViewport *vp)
1463 struct LatLon lnw, lse;
1464 vik_viewport_screen_to_coord ( vp, -20, -20, &nw );
1465 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp)+20, vik_viewport_get_width(vp)+20, &se );
1466 vik_coord_to_latlon ( &nw, &lnw );
1467 vik_coord_to_latlon ( &se, &lse );
1468 if ( vgl->realtime_fix.fix.latitude > lse.lat &&
1469 vgl->realtime_fix.fix.latitude < lnw.lat &&
1470 vgl->realtime_fix.fix.longitude > lnw.lon &&
1471 vgl->realtime_fix.fix.longitude < lse.lon &&
1472 !isnan (vgl->realtime_fix.fix.track) ) {
1475 gint half_back_x, half_back_y;
1476 gint half_back_bg_x, half_back_bg_y;
1479 gint side1_x, side1_y, side2_x, side2_y;
1480 gint side1bg_x, side1bg_y, side2bg_x, side2bg_y;
1482 ll.lat = vgl->realtime_fix.fix.latitude;
1483 ll.lon = vgl->realtime_fix.fix.longitude;
1484 vik_coord_load_from_latlon ( &gps, vik_viewport_get_coord_mode(vp), &ll);
1485 vik_viewport_coord_to_screen ( vp, &gps, &x, &y );
1487 gdouble heading_cos = cos(DEG2RAD(vgl->realtime_fix.fix.track));
1488 gdouble heading_sin = sin(DEG2RAD(vgl->realtime_fix.fix.track));
1490 half_back_y = y+8*heading_cos;
1491 half_back_x = x-8*heading_sin;
1492 half_back_bg_y = y+10*heading_cos;
1493 half_back_bg_x = x-10*heading_sin;
1495 pt_y = half_back_y-24*heading_cos;
1496 pt_x = half_back_x+24*heading_sin;
1497 //ptbg_y = half_back_bg_y-28*heading_cos;
1498 ptbg_x = half_back_bg_x+28*heading_sin;
1500 side1_y = half_back_y+9*heading_sin;
1501 side1_x = half_back_x+9*heading_cos;
1502 side1bg_y = half_back_bg_y+11*heading_sin;
1503 side1bg_x = half_back_bg_x+11*heading_cos;
1505 side2_y = half_back_y-9*heading_sin;
1506 side2_x = half_back_x-9*heading_cos;
1507 side2bg_y = half_back_bg_y-11*heading_sin;
1508 side2bg_x = half_back_bg_x-11*heading_cos;
1510 GdkPoint trian[3] = { { pt_x, pt_y }, {side1_x, side1_y}, {side2_x, side2_y} };
1511 GdkPoint trian_bg[3] = { { ptbg_x, pt_y }, {side1bg_x, side1bg_y}, {side2bg_x, side2bg_y} };
1513 vik_viewport_draw_polygon ( vp, vgl->realtime_track_bg_gc, TRUE, trian_bg, 3 );
1514 vik_viewport_draw_polygon ( vp, vgl->realtime_track_gc, TRUE, trian, 3 );
1515 vik_viewport_draw_rectangle ( vp,
1516 (vgl->realtime_fix.fix.mode > MODE_2D) ? vgl->realtime_track_pt2_gc : vgl->realtime_track_pt1_gc,
1517 TRUE, x-2, y-2, 4, 4 );
1518 //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;
1522 static VikTrackpoint* create_realtime_trackpoint(VikGpsLayer *vgl, gboolean forced)
1527 /* Note that fix.time is a double, but it should not affect the precision
1529 time_t cur_timestamp = vgl->realtime_fix.fix.time;
1530 time_t last_timestamp = vgl->last_fix.fix.time;
1532 if (cur_timestamp < last_timestamp) {
1536 if (vgl->realtime_record && vgl->realtime_fix.dirty) {
1537 gboolean replace = FALSE;
1538 int heading = isnan(vgl->realtime_fix.fix.track) ? 0 : (int)floor(vgl->realtime_fix.fix.track);
1539 int last_heading = isnan(vgl->last_fix.fix.track) ? 0 : (int)floor(vgl->last_fix.fix.track);
1540 int alt = isnan(vgl->realtime_fix.fix.altitude) ? VIK_DEFAULT_ALTITUDE : floor(vgl->realtime_fix.fix.altitude);
1541 int last_alt = isnan(vgl->last_fix.fix.altitude) ? VIK_DEFAULT_ALTITUDE : floor(vgl->last_fix.fix.altitude);
1542 if (((last_tp = g_list_last(vgl->realtime_track->trackpoints)) != NULL) &&
1543 (vgl->realtime_fix.fix.mode > MODE_2D) &&
1544 (vgl->last_fix.fix.mode <= MODE_2D) &&
1545 ((cur_timestamp - last_timestamp) < 2)) {
1546 g_free(last_tp->data);
1547 vgl->realtime_track->trackpoints = g_list_delete_link(vgl->realtime_track->trackpoints, last_tp);
1551 ((cur_timestamp != last_timestamp) &&
1553 ((heading < last_heading) && (heading < (last_heading - 3))) ||
1554 ((heading > last_heading) && (heading > (last_heading + 3))) ||
1555 ((alt != VIK_DEFAULT_ALTITUDE) && (alt != last_alt)))))) {
1556 /* TODO: check for new segments */
1557 VikTrackpoint *tp = vik_trackpoint_new();
1558 tp->newsegment = FALSE;
1559 tp->has_timestamp = TRUE;
1560 tp->timestamp = vgl->realtime_fix.fix.time;
1562 /* speed only available for 3D fix. Check for NAN when use this speed */
1563 tp->speed = vgl->realtime_fix.fix.speed;
1564 tp->course = vgl->realtime_fix.fix.track;
1565 tp->nsats = vgl->realtime_fix.satellites_used;
1566 tp->fix_mode = vgl->realtime_fix.fix.mode;
1568 ll.lat = vgl->realtime_fix.fix.latitude;
1569 ll.lon = vgl->realtime_fix.fix.longitude;
1570 vik_coord_load_from_latlon(&tp->coord,
1571 vik_trw_layer_get_coord_mode(vgl->trw_children[TRW_REALTIME]), &ll);
1573 vik_track_add_trackpoint ( vgl->realtime_track, tp, TRUE ); // Ensure bounds is recalculated
1574 vgl->realtime_fix.dirty = FALSE;
1575 vgl->realtime_fix.satellites_used = 0;
1576 vgl->last_fix = vgl->realtime_fix;
1583 #define VIK_SETTINGS_GPS_STATUSBAR_FORMAT "gps_statusbar_format"
1585 static void update_statusbar ( VikGpsLayer *vgl, VikWindow *vw )
1587 gchar *statusbar_format_code = NULL;
1588 gboolean need2free = FALSE;
1589 if ( !a_settings_get_string ( VIK_SETTINGS_GPS_STATUSBAR_FORMAT, &statusbar_format_code ) ) {
1590 // Otherwise use default
1591 statusbar_format_code = g_strdup ( "GSA" );
1595 gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, vgl->trkpt, vgl->trkpt_prev, vgl->realtime_track, vgl->last_fix.fix.climb );
1596 vik_statusbar_set_message ( vik_window_get_statusbar (vw), VIK_STATUSBAR_INFO, msg );
1600 g_free ( statusbar_format_code );
1604 static void gpsd_raw_hook(VglGpsd *vgpsd, gchar *data)
1606 gboolean update_all = FALSE;
1607 VikGpsLayer *vgl = vgpsd->vgl;
1609 if (!vgl->realtime_tracking) {
1610 g_warning("%s: receiving GPS data while not in realtime mode", __PRETTY_FUNCTION__);
1614 if ((vgpsd->gpsd.fix.mode >= MODE_2D) &&
1615 !isnan(vgpsd->gpsd.fix.latitude) &&
1616 !isnan(vgpsd->gpsd.fix.longitude)) {
1618 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1619 VikViewport *vvp = vik_window_viewport(vw);
1620 vgl->realtime_fix.fix = vgpsd->gpsd.fix;
1621 vgl->realtime_fix.satellites_used = vgpsd->gpsd.satellites_used;
1622 vgl->realtime_fix.dirty = TRUE;
1625 VikCoord vehicle_coord;
1627 ll.lat = vgl->realtime_fix.fix.latitude;
1628 ll.lon = vgl->realtime_fix.fix.longitude;
1629 vik_coord_load_from_latlon(&vehicle_coord,
1630 vik_trw_layer_get_coord_mode(vgl->trw_children[TRW_REALTIME]), &ll);
1632 if ((vgl->vehicle_position == VEHICLE_POSITION_CENTERED) ||
1633 (vgl->realtime_jump_to_start && vgl->first_realtime_trackpoint)) {
1634 vik_viewport_set_center_coord(vvp, &vehicle_coord, FALSE);
1637 else if (vgl->vehicle_position == VEHICLE_POSITION_ON_SCREEN) {
1640 const int px = 20; /* adjust ment in pixels to make sure vehicle is inside the box */
1641 gint width = vik_viewport_get_width(vvp);
1642 gint height = vik_viewport_get_height(vvp);
1645 vik_viewport_coord_to_screen(vvp, &vehicle_coord, &vx, &vy);
1647 if (vx < (width/hdiv))
1648 vik_viewport_set_center_screen(vvp, vx - width/2 + width/hdiv + px, vy);
1649 else if (vx > (width - width/hdiv))
1650 vik_viewport_set_center_screen(vvp, vx + width/2 - width/hdiv - px, vy);
1651 else if (vy < (height/vdiv))
1652 vik_viewport_set_center_screen(vvp, vx, vy - height/2 + height/vdiv + px);
1653 else if (vy > (height - height/vdiv))
1654 vik_viewport_set_center_screen(vvp, vx, vy + height/2 - height/vdiv - px);
1659 vgl->first_realtime_trackpoint = FALSE;
1661 vgl->trkpt = create_realtime_trackpoint ( vgl, FALSE );
1664 if ( vgl->realtime_update_statusbar )
1665 update_statusbar ( vgl, vw );
1666 vgl->trkpt_prev = vgl->trkpt;
1669 vik_layer_emit_update ( update_all ? VIK_LAYER(vgl) : VIK_LAYER(vgl->trw_children[TRW_REALTIME]) ); // NB update from background thread
1673 static gboolean gpsd_data_available(GIOChannel *source, GIOCondition condition, gpointer data)
1675 VikGpsLayer *vgl = data;
1676 if (condition == G_IO_IN) {
1677 #if GPSD_API_MAJOR_VERSION == 3 || GPSD_API_MAJOR_VERSION == 4
1678 if (!gps_poll(&vgl->vgpsd->gpsd)) {
1679 #elif GPSD_API_MAJOR_VERSION == 5 || GPSD_API_MAJOR_VERSION == 6
1680 if (gps_read(&vgl->vgpsd->gpsd) > -1) {
1681 // Reuse old function to perform operations on the new GPS data
1682 gpsd_raw_hook(vgl->vgpsd, NULL);
1689 g_warning("Disconnected from gpsd. Trying to reconnect");
1690 rt_gpsd_disconnect(vgl);
1691 rt_gpsd_connect(vgl, FALSE);
1694 return FALSE; /* no further calling */
1697 static gchar *make_track_name(VikTrwLayer *vtl)
1699 const gchar basename[] = "REALTIME";
1700 const gint bufsize = sizeof(basename) + 5;
1701 gchar *name = g_malloc(bufsize);
1702 strcpy(name, basename);
1705 while (vik_trw_layer_get_track(vtl, name) != NULL) {
1706 g_snprintf(name, bufsize, "%s#%d", basename, i);
1713 static gboolean rt_gpsd_try_connect(gpointer *data)
1715 VikGpsLayer *vgl = (VikGpsLayer *)data;
1716 #if GPSD_API_MAJOR_VERSION == 3
1717 struct gps_data_t *gpsd = gps_open(vgl->gpsd_host, vgl->gpsd_port);
1720 #elif GPSD_API_MAJOR_VERSION == 4
1721 vgl->vgpsd = g_malloc(sizeof(VglGpsd));
1723 if (gps_open_r(vgl->gpsd_host, vgl->gpsd_port, /*(struct gps_data_t *)*/vgl->vgpsd) != 0) {
1724 #elif GPSD_API_MAJOR_VERSION == 5 || GPSD_API_MAJOR_VERSION == 6
1725 vgl->vgpsd = g_malloc(sizeof(VglGpsd));
1726 if (gps_open(vgl->gpsd_host, vgl->gpsd_port, &vgl->vgpsd->gpsd) != 0) {
1728 // Delibrately break compilation...
1730 g_warning("Failed to connect to gpsd at %s (port %s). Will retry in %d seconds",
1731 vgl->gpsd_host, vgl->gpsd_port, vgl->gpsd_retry_interval);
1732 return TRUE; /* keep timer running */
1735 #if GPSD_API_MAJOR_VERSION == 3
1736 vgl->vgpsd = realloc(gpsd, sizeof(VglGpsd));
1738 vgl->vgpsd->vgl = vgl;
1740 vgl->realtime_fix.dirty = vgl->last_fix.dirty = FALSE;
1741 /* track alt/time graph uses VIK_DEFAULT_ALTITUDE (0.0) as invalid */
1742 vgl->realtime_fix.fix.altitude = vgl->last_fix.fix.altitude = VIK_DEFAULT_ALTITUDE;
1743 vgl->realtime_fix.fix.speed = vgl->last_fix.fix.speed = NAN;
1745 if (vgl->realtime_record) {
1746 VikTrwLayer *vtl = vgl->trw_children[TRW_REALTIME];
1747 vgl->realtime_track = vik_track_new();
1748 vgl->realtime_track->visible = TRUE;
1749 vik_trw_layer_add_track(vtl, make_track_name(vtl), vgl->realtime_track);
1752 #if GPSD_API_MAJOR_VERSION == 3 || GPSD_API_MAJOR_VERSION == 4
1753 gps_set_raw_hook(&vgl->vgpsd->gpsd, gpsd_raw_hook);
1756 vgl->realtime_io_channel = g_io_channel_unix_new(vgl->vgpsd->gpsd.gps_fd);
1757 vgl->realtime_io_watch_id = g_io_add_watch( vgl->realtime_io_channel,
1758 G_IO_IN | G_IO_ERR | G_IO_HUP, gpsd_data_available, vgl);
1760 #if GPSD_API_MAJOR_VERSION == 3
1761 gps_query(&vgl->vgpsd->gpsd, "w+x");
1763 #if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5 || GPSD_API_MAJOR_VERSION == 6
1764 gps_stream(&vgl->vgpsd->gpsd, WATCH_ENABLE, NULL);
1767 return FALSE; /* no longer called by timeout */
1770 static gboolean rt_ask_retry(VikGpsLayer *vgl)
1772 GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER(vgl),
1773 GTK_DIALOG_DESTROY_WITH_PARENT,
1774 GTK_MESSAGE_QUESTION,
1776 "Failed to connect to gpsd at %s (port %s)\n"
1777 "Should Viking keep trying (every %d seconds)?",
1778 vgl->gpsd_host, vgl->gpsd_port,
1779 vgl->gpsd_retry_interval);
1781 gint res = gtk_dialog_run(GTK_DIALOG(dialog));
1782 gtk_widget_destroy(dialog);
1783 return (res == GTK_RESPONSE_YES);
1786 static gboolean rt_gpsd_connect(VikGpsLayer *vgl, gboolean ask_if_failed)
1788 vgl->realtime_retry_timer = 0;
1789 if (rt_gpsd_try_connect((gpointer *)vgl)) {
1790 if (vgl->gpsd_retry_interval <= 0) {
1791 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);
1794 else if (ask_if_failed && !rt_ask_retry(vgl))
1797 vgl->realtime_retry_timer = g_timeout_add_seconds(vgl->gpsd_retry_interval,
1798 (GSourceFunc)rt_gpsd_try_connect, (gpointer *)vgl);
1803 static void rt_gpsd_disconnect(VikGpsLayer *vgl)
1805 if (vgl->realtime_retry_timer) {
1806 g_source_remove(vgl->realtime_retry_timer);
1807 vgl->realtime_retry_timer = 0;
1809 if (vgl->realtime_io_watch_id) {
1810 g_source_remove(vgl->realtime_io_watch_id);
1811 vgl->realtime_io_watch_id = 0;
1813 if (vgl->realtime_io_channel) {
1814 GError *error = NULL;
1815 g_io_channel_shutdown (vgl->realtime_io_channel, FALSE, &error);
1816 vgl->realtime_io_channel = NULL;
1819 #if GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5 || GPSD_API_MAJOR_VERSION == 6
1820 gps_stream(&vgl->vgpsd->gpsd, WATCH_DISABLE, NULL);
1822 gps_close(&vgl->vgpsd->gpsd);
1823 #if GPSD_API_MAJOR_VERSION == 3
1825 #elif GPSD_API_MAJOR_VERSION == 4 || GPSD_API_MAJOR_VERSION == 5 || GPSD_API_MAJOR_VERSION == 6
1831 if (vgl->realtime_record && vgl->realtime_track) {
1832 if ((vgl->realtime_track->trackpoints == NULL) || (vgl->realtime_track->trackpoints->next == NULL))
1833 vik_trw_layer_delete_track(vgl->trw_children[TRW_REALTIME], vgl->realtime_track);
1834 vgl->realtime_track = NULL;
1838 static void gps_start_stop_tracking_cb( gpointer layer_and_vlp[2])
1840 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1841 vgl->realtime_tracking = (vgl->realtime_tracking == FALSE);
1843 /* Make sure we are still in the boat with libgps */
1844 g_assert((VIK_GPS_MODE_2D == MODE_2D) && (VIK_GPS_MODE_3D == MODE_3D));
1846 if (vgl->realtime_tracking) {
1847 vgl->first_realtime_trackpoint = TRUE;
1848 if (!rt_gpsd_connect(vgl, TRUE)) {
1849 vgl->first_realtime_trackpoint = FALSE;
1850 vgl->realtime_tracking = FALSE;
1854 else { /* stop realtime tracking */
1855 vgl->first_realtime_trackpoint = FALSE;
1857 rt_gpsd_disconnect(vgl);
1860 #endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */