]> git.street.me.uk Git - andy/viking.git/blame - src/vikgpslayer.c
Diasable buttons on Track Properties Dialog when not needed.
[andy/viking.git] / src / vikgpslayer.c
CommitLineData
b364d6bc
QT
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
58a642b6
GB
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
b87d3952
QT
26#include <stdlib.h>
27#include <math.h>
b364d6bc
QT
28#include "viking.h"
29#include "vikgpslayer_pixmap.h"
30#include "babel.h"
31
32#include <string.h>
33#include <glib.h>
34#include <glib/gprintf.h>
001a86db 35#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952 36#include <gps.h>
58a642b6 37#endif
b364d6bc
QT
38
39#define DISCONNECT_UPDATE_SIGNAL(vl, val) g_signal_handlers_disconnect_matched(vl, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, val)
fdca5edb
QT
40static VikGpsLayer *vik_gps_layer_create (VikViewport *vp);
41static void vik_gps_layer_realize ( VikGpsLayer *val, VikTreeview *vt, GtkTreeIter *layer_iter );
42static void vik_gps_layer_free ( VikGpsLayer *val );
43static void vik_gps_layer_draw ( VikGpsLayer *val, gpointer data );
44VikGpsLayer *vik_gps_layer_new ();
b364d6bc 45
b364d6bc
QT
46static void gps_layer_marshall( VikGpsLayer *val, guint8 **data, gint *len );
47static VikGpsLayer *gps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
48static gboolean gps_layer_set_param ( VikGpsLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp );
49static VikLayerParamData gps_layer_get_param ( VikGpsLayer *vgl, guint16 id );
50
51static void gps_layer_change_coord_mode ( VikGpsLayer *val, VikCoordMode mode );
52static void gps_layer_add_menu_items( VikGpsLayer *vtl, GtkMenu *menu, gpointer vlp );
53static void gps_layer_drag_drop_request ( VikGpsLayer *val_src, VikGpsLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
54
b364d6bc
QT
55static void gps_upload_cb( gpointer layer_and_vlp[2] );
56static void gps_download_cb( gpointer layer_and_vlp[2] );
700b0908
QT
57static void gps_empty_upload_cb( gpointer layer_and_vlp[2] );
58static void gps_empty_download_cb( gpointer layer_and_vlp[2] );
59static void gps_empty_all_cb( gpointer layer_and_vlp[2] );
001a86db 60#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952 61static void gps_start_stop_tracking_cb( gpointer layer_and_vlp[2] );
001a86db 62static void realtime_tracking_draw(VikGpsLayer *vgl, VikViewport *vp);
58a642b6 63#endif
b364d6bc
QT
64
65typedef enum {GARMIN_P = 0, MAGELLAN_P, NUM_PROTOCOLS} vik_gps_proto;
66static gchar * params_protocols[] = {"Garmin", "Magellan", NULL};
67static gchar * protocols_args[] = {"garmin", "magellan"};
68/*#define NUM_PROTOCOLS (sizeof(params_protocols)/sizeof(params_protocols[0]) - 1) */
7963d365 69static gchar * params_ports[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyUSB0", "/dev/ttyUSB1", "usb:", NULL};
b364d6bc
QT
70#define NUM_PORTS (sizeof(params_ports)/sizeof(params_ports[0]) - 1)
71typedef enum {GPS_DOWN=0, GPS_UP} gps_dir;
72
73typedef struct {
74 GMutex *mutex;
75 gps_dir direction;
76 gchar *port;
77 gboolean ok;
78 gint total_count;
79 gint count;
80 VikTrwLayer *vtl;
81 gchar *cmd_args;
82 gchar * window_title;
83 GtkWidget *dialog;
84 GtkWidget *status_label;
85 GtkWidget *gps_label;
86 GtkWidget *ver_label;
87 GtkWidget *id_label;
88 GtkWidget *wp_label;
89 GtkWidget *progress_label;
90 GtkWidget *trk_label;
91} GpsSession;
92static void gps_session_delete(GpsSession *sess);
93
58a642b6
GB
94static gchar *params_groups[] = {
95 "Data Mode",
001a86db 96#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
58a642b6
GB
97 "Realtime Tracking Mode",
98#endif
99};
100
b87d3952
QT
101enum {GROUP_DATA_MODE, GROUP_REALTIME_MODE};
102
b364d6bc 103static VikLayerParam gps_layer_params[] = {
b87d3952
QT
104 { "gps_protocol", VIK_LAYER_PARAM_UINT, GROUP_DATA_MODE, "GPS Protocol:", VIK_LAYER_WIDGET_COMBOBOX, params_protocols, NULL},
105 { "gps_port", VIK_LAYER_PARAM_UINT, GROUP_DATA_MODE, "Serial Port:", VIK_LAYER_WIDGET_COMBOBOX, params_ports, NULL},
106
001a86db 107#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
108 { "record_tracking", VIK_LAYER_PARAM_BOOLEAN, GROUP_REALTIME_MODE, "Recording tracks", VIK_LAYER_WIDGET_CHECKBUTTON},
109 { "center_start_tracking", VIK_LAYER_PARAM_BOOLEAN, GROUP_REALTIME_MODE, "Jump to current position on start", VIK_LAYER_WIDGET_CHECKBUTTON},
110 { "centered_tracking", VIK_LAYER_PARAM_BOOLEAN, GROUP_REALTIME_MODE, "Keep current position at center", VIK_LAYER_WIDGET_CHECKBUTTON},
111 { "gpsd_host", VIK_LAYER_PARAM_STRING, GROUP_REALTIME_MODE, "Gpsd Host:", VIK_LAYER_WIDGET_ENTRY},
112 { "gpsd_port", VIK_LAYER_PARAM_STRING, GROUP_REALTIME_MODE, "Gpsd Port:", VIK_LAYER_WIDGET_ENTRY},
001a86db 113#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc 114};
58a642b6
GB
115enum {
116 PARAM_PROTOCOL=0, PARAM_PORT,
001a86db 117#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
58a642b6 118 PARAM_REALTIME_REC, PARAM_REALTIME_CENTER_START, PARAM_REALTIME_CENTERED, PARAM_GPSD_HOST, PARAM_GPSD_PORT,
001a86db 119#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
58a642b6 120 NUM_PARAMS};
b364d6bc
QT
121
122VikLayerInterface vik_gps_layer_interface = {
123 "GPS",
124 &gpslayer_pixbuf,
125
126 NULL,
127 0,
128
129 gps_layer_params,
130 NUM_PARAMS,
b87d3952
QT
131 params_groups,
132 sizeof(params_groups)/sizeof(params_groups[0]),
b364d6bc 133
5a4a28bf
QT
134 VIK_MENU_ITEM_ALL & ~(VIK_MENU_ITEM_CUT|VIK_MENU_ITEM_COPY),
135
b364d6bc
QT
136 (VikLayerFuncCreate) vik_gps_layer_create,
137 (VikLayerFuncRealize) vik_gps_layer_realize,
138 (VikLayerFuncPostRead) NULL,
139 (VikLayerFuncFree) vik_gps_layer_free,
140
141 (VikLayerFuncProperties) NULL,
142 (VikLayerFuncDraw) vik_gps_layer_draw,
143 (VikLayerFuncChangeCoordMode) gps_layer_change_coord_mode,
144
20c7a3a0
QT
145 (VikLayerFuncSetMenuItemsSelection) NULL,
146 (VikLayerFuncGetMenuItemsSelection) NULL,
147
b364d6bc
QT
148 (VikLayerFuncAddMenuItems) gps_layer_add_menu_items,
149 (VikLayerFuncSublayerAddMenuItems) NULL,
150
151 (VikLayerFuncSublayerRenameRequest) NULL,
152 (VikLayerFuncSublayerToggleVisible) NULL,
153
b364d6bc
QT
154 (VikLayerFuncMarshall) gps_layer_marshall,
155 (VikLayerFuncUnmarshall) gps_layer_unmarshall,
156
157 (VikLayerFuncSetParam) gps_layer_set_param,
158 (VikLayerFuncGetParam) gps_layer_get_param,
159
160 (VikLayerFuncReadFileData) NULL,
161 (VikLayerFuncWriteFileData) NULL,
162
163 (VikLayerFuncDeleteItem) NULL,
164 (VikLayerFuncCopyItem) NULL,
165 (VikLayerFuncPasteItem) NULL,
166 (VikLayerFuncFreeCopiedItem) NULL,
167 (VikLayerFuncDragDropRequest) gps_layer_drag_drop_request,
168};
169
58a642b6 170enum {TRW_DOWNLOAD=0, TRW_UPLOAD,
001a86db 171#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
58a642b6
GB
172 TRW_REALTIME,
173#endif
174 NUM_TRW};
175static gchar * trw_names[] = {
176 "GPS Download", "GPS Upload",
001a86db 177#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
58a642b6
GB
178 "GPS Realtime Tracking",
179#endif
180};
b87d3952 181
001a86db 182#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
183typedef struct {
184 struct gps_data_t gpsd;
185 VikGpsLayer *vgl;
186} VglGpsd;
187
188typedef struct {
c4e61875 189 struct gps_fix_t fix;
a2817d3c 190 gint satellites_used;
b87d3952
QT
191 gboolean dirty; /* needs to be saved */
192} GpsFix;
001a86db 193#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b87d3952 194
b364d6bc
QT
195struct _VikGpsLayer {
196 VikLayer vl;
197 VikTrwLayer * trw_children[NUM_TRW];
f253a6a6
QT
198 GList * children; /* used only for writing file */
199 int cur_read_child; /* used only for reading file */
001a86db 200#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
201 VglGpsd *vgpsd;
202 gboolean realtime_tracking;
203 GMutex *realtime_tracking_mutex;
204 GpsFix realtime_fix;
205 GpsFix last_fix;
206
207 enum unit realtime_gpsd_unit;
208
209 VikTrack *realtime_track;
210 gchar *realtime_track_name;
211
212 GIOChannel *realtime_io_channel;
213 guint realtime_io_watch_id;
214 GdkGC *realtime_track_gc;
215 GdkGC *realtime_track_bg_gc;
216 GdkGC *realtime_track_pt_gc;
217 GdkGC *realtime_track_pt1_gc;
218 GdkGC *realtime_track_pt2_gc;
219
b364d6bc 220 /* params */
b87d3952
QT
221 gchar *gpsd_host;
222 gchar *gpsd_port;
223 gboolean realtime_record;
224 gboolean realtime_jump_to_start;
225 gboolean realtime_keep_at_center;
001a86db
QT
226#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
227 guint protocol_id;
228 guint serial_port_id;
b364d6bc
QT
229};
230
231GType vik_gps_layer_get_type ()
232{
233 static GType val_type = 0;
234
235 if (!val_type)
236 {
237 static const GTypeInfo val_info =
238 {
239 sizeof (VikGpsLayerClass),
240 NULL, /* base_init */
241 NULL, /* base_finalize */
242 NULL, /* class init */
243 NULL, /* class_finalize */
244 NULL, /* class_data */
245 sizeof (VikGpsLayer),
246 0,
247 NULL /* instance init */
248 };
249 val_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGpsLayer", &val_info, 0 );
250 }
251
252 return val_type;
253}
254
fdca5edb 255static VikGpsLayer *vik_gps_layer_create (VikViewport *vp)
b364d6bc 256{
c4e61875
QT
257 int i;
258
b87d3952 259 VikGpsLayer *rv = vik_gps_layer_new (vp);
b364d6bc 260 vik_layer_rename ( VIK_LAYER(rv), vik_gps_layer_interface.name );
c4e61875
QT
261
262 for (i = 0; i < NUM_TRW; i++) {
263 rv->trw_children[i] = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vp, NULL, FALSE ));
264 vik_layer_set_menu_items_selection(VIK_LAYER(rv->trw_children[i]), VIK_MENU_ITEM_ALL & ~(VIK_MENU_ITEM_CUT|VIK_MENU_ITEM_DELETE));
265 }
b364d6bc
QT
266 return rv;
267}
268
b364d6bc
QT
269/* "Copy" */
270static void gps_layer_marshall( VikGpsLayer *vgl, guint8 **data, gint *datalen )
271{
272 VikLayer *child_layer;
273 guint8 *ld;
274 gint ll;
275 GByteArray* b = g_byte_array_new ();
276 gint len;
277 gint i;
278
279#define alm_append(obj, sz) \
280 len = (sz); \
281 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
282 g_byte_array_append ( b, (guint8 *)(obj), len );
283
284 vik_layer_marshall_params(VIK_LAYER(vgl), &ld, &ll);
285 alm_append(ld, ll);
286 g_free(ld);
287
288 for (i = 0; i < NUM_TRW; i++) {
289 child_layer = VIK_LAYER(vgl->trw_children[i]);
290 vik_layer_marshall(child_layer, &ld, &ll);
291 if (ld) {
292 alm_append(ld, ll);
293 g_free(ld);
294 }
295 }
296 *data = b->data;
297 *datalen = b->len;
298 g_byte_array_free(b, FALSE);
299#undef alm_append
300}
301
302/* "Paste" */
303static VikGpsLayer *gps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
304{
305#define alm_size (*(gint *)data)
306#define alm_next \
307 len -= sizeof(gint) + alm_size; \
308 data += sizeof(gint) + alm_size;
309
310 VikGpsLayer *rv = vik_gps_layer_new();
311 VikLayer *child_layer;
312 gint i;
313
314 vik_layer_unmarshall_params ( VIK_LAYER(rv), data+sizeof(gint), alm_size, vvp );
315 alm_next;
316
317 i = 0;
318 while (len>0 && i < NUM_TRW) {
319 child_layer = vik_layer_unmarshall ( data + sizeof(gint), alm_size, vvp );
320 if (child_layer) {
fdca5edb 321 rv->trw_children[i++] = (VikTrwLayer *)child_layer;
b87d3952 322 g_signal_connect_swapped ( G_OBJECT(child_layer), "update", G_CALLBACK(vik_layer_emit_update_secondary), rv );
b364d6bc
QT
323 }
324 alm_next;
325 }
326 // g_print("gps_layer_unmarshall ended with len=%d\n", len);
327 g_assert(len == 0);
328 return rv;
329#undef alm_size
330#undef alm_next
331}
332
333static gboolean gps_layer_set_param ( VikGpsLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp )
334{
335 switch ( id )
336 {
b87d3952 337 /* TODO: gpsd_host, gpsd_port */
b364d6bc
QT
338 case PARAM_PROTOCOL:
339 if (data.u < NUM_PROTOCOLS)
340 vgl->protocol_id = data.u;
341 else
342 g_warning("Unknown GPS Protocol");
343 break;
344 case PARAM_PORT:
345 if (data.u < NUM_PORTS)
346 vgl->serial_port_id = data.u;
347 else
348 g_warning("Unknown serial port device");
349 break;
001a86db 350#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
351 case PARAM_GPSD_HOST:
352 if (vgl->gpsd_host)
353 g_free(vgl->gpsd_host);
354 vgl->gpsd_host = g_strdup(data.s);
355 break;
356 case PARAM_GPSD_PORT:
357 if (vgl->gpsd_port)
358 g_free(vgl->gpsd_port);
359 vgl->gpsd_port = g_strdup(data.s); /* TODO: check for number */
360 break;
361 case PARAM_REALTIME_REC:
362 vgl->realtime_record = data.b;
363 break;
364 case PARAM_REALTIME_CENTER_START:
365 vgl->realtime_jump_to_start = data.b;
366 break;
367 case PARAM_REALTIME_CENTERED:
368 vgl->realtime_keep_at_center = data.b;
369 break;
001a86db 370#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b87d3952
QT
371 default:
372 g_warning("gps_layer_set_param(): unknown parameter");
b364d6bc
QT
373 }
374
375 return TRUE;
376}
377
378static VikLayerParamData gps_layer_get_param ( VikGpsLayer *vgl, guint16 id )
379{
380 VikLayerParamData rv;
381 switch ( id )
382 {
b87d3952 383 /* TODO: gpsd_host, gpsd_port */
b364d6bc
QT
384 case PARAM_PROTOCOL:
385 rv.u = vgl->protocol_id;
386 break;
387 case PARAM_PORT:
388 rv.u = vgl->serial_port_id;
389 break;
001a86db 390#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
391 case PARAM_GPSD_HOST:
392 rv.s = vgl->gpsd_host ? vgl->gpsd_host : "";
393 break;
394 case PARAM_GPSD_PORT:
395 rv.s = vgl->gpsd_port ? vgl->gpsd_port : g_strdup(DEFAULT_GPSD_PORT);
396 break;
397 case PARAM_REALTIME_REC:
398 rv.b = vgl->realtime_record;
399 break;
400 case PARAM_REALTIME_CENTER_START:
401 rv.b = vgl->realtime_jump_to_start;
402 break;
403 case PARAM_REALTIME_CENTERED:
404 rv.b = vgl->realtime_keep_at_center;
405 break;
001a86db 406#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc
QT
407 default:
408 g_warning("gps_layer_get_param(): unknown parameter");
409 }
410
b364d6bc
QT
411 return rv;
412}
413
b87d3952 414VikGpsLayer *vik_gps_layer_new (VikViewport *vp)
b364d6bc
QT
415{
416 gint i;
417 VikGpsLayer *vgl = VIK_GPS_LAYER ( g_object_new ( VIK_GPS_LAYER_TYPE, NULL ) );
418 vik_layer_init ( VIK_LAYER(vgl), VIK_LAYER_GPS );
419 for (i = 0; i < NUM_TRW; i++) {
420 vgl->trw_children[i] = NULL;
421 }
7886de28 422 vgl->children = NULL;
f253a6a6 423 vgl->cur_read_child = 0;
b364d6bc 424
001a86db 425#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
426 vgl->realtime_tracking_mutex = g_mutex_new();
427 vgl->realtime_tracking = FALSE;
428 vgl->vgpsd = NULL;
429 vgl->realtime_track_gc = vik_viewport_new_gc ( vp, "#203070", 2 );
430 vgl->realtime_track_bg_gc = vik_viewport_new_gc ( vp, "grey", 2 );
431 vgl->realtime_track_pt1_gc = vik_viewport_new_gc ( vp, "red", 2 );
432 vgl->realtime_track_pt2_gc = vik_viewport_new_gc ( vp, "green", 2 );
433 vgl->realtime_track_pt_gc = vgl->realtime_track_pt1_gc;
434 vgl->realtime_gpsd_unit = gpsd_units();
435 // fprintf(stderr, "DEBUG: gpsd_unit = %d\n", vgl->realtime_gpsd_unit);
436 vgl->realtime_track = NULL;
437
b364d6bc 438 /* Setting params here */
b87d3952
QT
439 vgl->gpsd_host = g_strdup("localhost");
440 vgl->gpsd_port = g_strdup(DEFAULT_GPSD_PORT);
441 vgl->realtime_record = TRUE;
442 vgl->realtime_jump_to_start = TRUE;
443 vgl->realtime_keep_at_center = FALSE;
001a86db
QT
444#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
445 vgl->protocol_id = 0;
446 vgl->serial_port_id = 0;
b364d6bc
QT
447
448 return vgl;
449}
450
fdca5edb 451static void vik_gps_layer_draw ( VikGpsLayer *vgl, gpointer data )
b364d6bc
QT
452{
453 gint i;
b87d3952
QT
454 VikLayer *vl;
455 VikLayer *trigger = VIK_LAYER(vik_viewport_get_trigger( VIK_VIEWPORT(data) ));
b364d6bc
QT
456
457 for (i = 0; i < NUM_TRW; i++) {
b87d3952
QT
458 vl = VIK_LAYER(vgl->trw_children[i]);
459 if (vl == trigger) {
460 if ( vik_viewport_get_half_drawn ( VIK_VIEWPORT(data) ) ) {
461 vik_viewport_set_half_drawn ( VIK_VIEWPORT(data), FALSE );
462 vik_viewport_snapshot_load( VIK_VIEWPORT(data) );
463 } else {
464 vik_viewport_snapshot_save( VIK_VIEWPORT(data) );
465 }
466 }
467 if (!vik_viewport_get_half_drawn( VIK_VIEWPORT(data)))
468 vik_layer_draw ( vl, data );
469 }
001a86db 470#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
471 if (vgl->realtime_tracking) {
472 if (VIK_LAYER(vgl) == trigger) {
473 if ( vik_viewport_get_half_drawn ( VIK_VIEWPORT(data) ) ) {
474 vik_viewport_set_half_drawn ( VIK_VIEWPORT(data), FALSE );
475 vik_viewport_snapshot_load( VIK_VIEWPORT(data) );
476 } else {
477 vik_viewport_snapshot_save( VIK_VIEWPORT(data) );
478 }
479 }
480 if (!vik_viewport_get_half_drawn( VIK_VIEWPORT(data)))
481 realtime_tracking_draw(vgl, VIK_VIEWPORT(data));
b364d6bc 482 }
001a86db 483#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc
QT
484}
485
486static void gps_layer_change_coord_mode ( VikGpsLayer *vgl, VikCoordMode mode )
487{
488 gint i;
489 for (i = 0; i < NUM_TRW; i++) {
2cebc318 490 vik_layer_change_coord_mode(VIK_LAYER(vgl->trw_children[i]), mode);
b364d6bc
QT
491 }
492}
493
494static void gps_layer_add_menu_items( VikGpsLayer *vgl, GtkMenu *menu, gpointer vlp )
495{
496 static gpointer pass_along[2];
497 GtkWidget *item;
498 pass_along[0] = vgl;
499 pass_along[1] = vlp;
500
501 item = gtk_menu_item_new();
502 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
503 gtk_widget_show ( item );
504
505 item = gtk_menu_item_new_with_label ( "Upload to GPS" );
506 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_upload_cb), pass_along );
507 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
508 gtk_widget_show ( item );
509
510 item = gtk_menu_item_new_with_label ( "Download from GPS" );
511 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_download_cb), pass_along );
512 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
513 gtk_widget_show ( item );
514
001a86db 515#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
516 item = gtk_menu_item_new_with_label ( vgl->realtime_tracking ?
517 "Stop realtime tracking" :
518 "Start realtime tracking" );
519 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_start_stop_tracking_cb), pass_along );
520 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
521 gtk_widget_show ( item );
522
700b0908
QT
523 item = gtk_menu_item_new();
524 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
525 gtk_widget_show ( item );
001a86db 526#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
700b0908
QT
527
528 item = gtk_menu_item_new_with_label ( "Empty Upload" );
529 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_upload_cb), pass_along );
530 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
531 gtk_widget_show ( item );
532
533 item = gtk_menu_item_new_with_label ( "Empty Download" );
534 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_download_cb), pass_along );
535 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
536 gtk_widget_show ( item );
537
538 item = gtk_menu_item_new_with_label ( "Empty All" );
539 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(gps_empty_all_cb), pass_along );
540 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
541 gtk_widget_show ( item );
542
b364d6bc
QT
543}
544
545static void disconnect_layer_signal ( VikLayer *vl, VikGpsLayer *vgl )
546{
b364d6bc
QT
547 g_assert(DISCONNECT_UPDATE_SIGNAL(vl,vgl)==1);
548}
549
fdca5edb 550static void vik_gps_layer_free ( VikGpsLayer *vgl )
b364d6bc 551{
b364d6bc
QT
552 gint i;
553 for (i = 0; i < NUM_TRW; i++) {
e03074ba 554 if (vgl->vl.realized)
fdca5edb 555 disconnect_layer_signal(VIK_LAYER(vgl->trw_children[i]), vgl);
b364d6bc
QT
556 g_object_unref(vgl->trw_children[i]);
557 }
001a86db 558#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
559 if (vgl->realtime_track_gc != NULL)
560 g_object_unref(vgl->realtime_track_gc);
561 if (vgl->realtime_track_bg_gc != NULL)
562 g_object_unref(vgl->realtime_track_bg_gc);
563 if (vgl->realtime_track_pt1_gc != NULL)
564 g_object_unref(vgl->realtime_track_pt1_gc);
565 if (vgl->realtime_track_pt2_gc != NULL)
566 g_object_unref(vgl->realtime_track_pt2_gc);
567 if (vgl->realtime_tracking_mutex != NULL)
568 g_mutex_free(vgl->realtime_tracking_mutex);
001a86db 569#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b364d6bc
QT
570}
571
b364d6bc
QT
572gboolean vik_gps_layer_delete ( VikGpsLayer *vgl, GtkTreeIter *iter )
573{
574 gint i;
575 VikLayer *l = VIK_LAYER( vik_treeview_item_get_pointer ( VIK_LAYER(vgl)->vt, iter ) );
576 gboolean was_visible = l->visible;
577
578 vik_treeview_item_delete ( VIK_LAYER(vgl)->vt, iter );
579 for (i = 0; i < NUM_TRW; i++) {
2cebc318 580 if (VIK_LAYER(vgl->trw_children[i]) == l)
b364d6bc
QT
581 vgl->trw_children[i] = NULL;
582 }
583 g_assert(DISCONNECT_UPDATE_SIGNAL(l,vgl)==1);
584 g_object_unref ( l );
585
586 return was_visible;
587}
588
fdca5edb 589static void vik_gps_layer_realize ( VikGpsLayer *vgl, VikTreeview *vt, GtkTreeIter *layer_iter )
b364d6bc
QT
590{
591 GtkTreeIter iter;
592 int ix;
593
594 for (ix = 0; ix < NUM_TRW; ix++) {
fdca5edb 595 VikLayer * trw = VIK_LAYER(vgl->trw_children[ix]);
b364d6bc
QT
596 vik_treeview_add_layer ( VIK_LAYER(vgl)->vt, layer_iter, &iter,
597 trw_names[ix], vgl,
598 trw, trw->type, trw->type );
599 if ( ! trw->visible )
600 vik_treeview_item_set_visible ( VIK_LAYER(vgl)->vt, &iter, FALSE );
601 vik_layer_realize ( trw, VIK_LAYER(vgl)->vt, &iter );
b87d3952 602 g_signal_connect_swapped ( G_OBJECT(trw), "update", G_CALLBACK(vik_layer_emit_update_secondary), vgl );
b364d6bc
QT
603 }
604}
605
7886de28
QT
606const GList *vik_gps_layer_get_children ( VikGpsLayer *vgl )
607{
608 int i;
609
610 if (vgl->children == NULL) {
611 for (i = NUM_TRW - 1; i >= 0; i--)
612 vgl->children = g_list_prepend(vgl->children, vgl->trw_children[i]);
613 }
614 return vgl->children;
615}
616
f253a6a6
QT
617VikTrwLayer * vik_gps_layer_get_a_child(VikGpsLayer *vgl)
618{
619 g_assert ((vgl->cur_read_child >= 0) && (vgl->cur_read_child < NUM_TRW));
620
621 VikTrwLayer * vtl = vgl->trw_children[vgl->cur_read_child];
622 if (++(vgl->cur_read_child) >= NUM_TRW)
623 vgl->cur_read_child = 0;
624 return(vtl);
625}
626
7886de28
QT
627gboolean vik_gps_layer_is_empty ( VikGpsLayer *vgl )
628{
629 if ( vgl->trw_children[0] )
630 return FALSE;
631 return TRUE;
632}
633
b364d6bc
QT
634static void gps_layer_drag_drop_request ( VikGpsLayer *val_src, VikGpsLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
635{
636 VikTreeview *vt = VIK_LAYER(val_src)->vt;
637 VikLayer *vl = vik_treeview_item_get_pointer(vt, src_item_iter);
638 GtkTreeIter dest_iter;
639 gchar *dp;
640 gboolean target_exists;
641
b364d6bc
QT
642 dp = gtk_tree_path_to_string(dest_path);
643 target_exists = vik_treeview_get_iter_from_path_str(vt, &dest_iter, dp);
644
645 /* vik_gps_layer_delete unrefs, but we don't want that here.
646 * we're still using the layer. */
647 g_object_ref ( vl );
648 vik_gps_layer_delete(val_src, src_item_iter);
649
b364d6bc
QT
650 g_free(dp);
651}
652
653static void gps_session_delete(GpsSession *sess)
654{
655 /* TODO */
656 g_mutex_free(sess->mutex);
657 g_free(sess->cmd_args);
658
659 g_free(sess);
660
661}
662
663static void set_total_count(gint cnt, GpsSession *sess)
664{
665 gchar s[128];
666 gdk_threads_enter();
667 g_mutex_lock(sess->mutex);
668 if (sess->ok) {
669 g_sprintf(s, "%s %d %s...",
670 (sess->direction == GPS_DOWN) ? "Downloading" : "Uploading", cnt,
671 (sess->progress_label == sess->wp_label) ? "waypoints" : "trackpoints");
672 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
673 gtk_widget_show ( sess->progress_label );
674 sess->total_count = cnt;
675 }
676 g_mutex_unlock(sess->mutex);
677 gdk_threads_leave();
678}
679
680static void set_current_count(gint cnt, GpsSession *sess)
681{
682 gchar s[128];
683 gchar *dir_str = (sess->direction == GPS_DOWN) ? "Downloaded" : "Uploaded";
684
685 gdk_threads_enter();
686 g_mutex_lock(sess->mutex);
687 if (sess->ok) {
688 if (cnt < sess->total_count) {
689 g_sprintf(s, "%s %d out of %d %s...", dir_str, cnt, sess->total_count, (sess->progress_label == sess->wp_label) ? "waypoints" : "trackpoints");
690 } else {
691 g_sprintf(s, "%s %d %s.", dir_str, cnt, (sess->progress_label == sess->wp_label) ? "waypoints" : "trackpoints");
692 }
693 gtk_label_set_text ( GTK_LABEL(sess->progress_label), s );
694 }
695 g_mutex_unlock(sess->mutex);
696 gdk_threads_leave();
697}
698
699static void set_gps_info(const gchar *info, GpsSession *sess)
700{
701 gchar s[256];
702 gdk_threads_enter();
703 g_mutex_lock(sess->mutex);
704 if (sess->ok) {
705 g_sprintf(s, "GPS Device: %s", info);
706 gtk_label_set_text ( GTK_LABEL(sess->gps_label), s );
707 }
708 g_mutex_unlock(sess->mutex);
709 gdk_threads_leave();
710}
711
712static void gps_download_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
713{
714 gchar *line;
715
716 gdk_threads_enter ();
717 g_mutex_lock(sess->mutex);
718 if (!sess->ok) {
719 g_mutex_unlock(sess->mutex);
720 gps_session_delete(sess);
721 gdk_threads_leave();
722 g_thread_exit ( NULL );
723 }
724 g_mutex_unlock(sess->mutex);
725 gdk_threads_leave ();
726
727 switch(c) {
728 case BABEL_DIAG_OUTPUT:
729 line = (gchar *)data;
730
731 /* tells us how many items there will be */
732 if (strstr(line, "Xfer Wpt")) {
733 sess->progress_label = sess->wp_label;
734 }
735 if (strstr(line, "Xfer Trk")) {
736 sess->progress_label = sess->trk_label;
737 }
738 if (strstr(line, "PRDDAT")) {
739 gchar **tokens = g_strsplit(line, " ", 0);
740 gchar info[128];
741 int ilen = 0;
742 int i;
c83b5ad9
QT
743 int n_tokens = 0;
744
745 while (tokens[n_tokens])
746 n_tokens++;
747
748 if (n_tokens > 8) {
749 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
750 guint ch;
751 sscanf(tokens[i], "%x", &ch);
752 info[ilen++] = ch;
753 }
754 info[ilen++] = 0;
755 set_gps_info(info, sess);
b364d6bc 756 }
c83b5ad9 757 g_strfreev(tokens);
b364d6bc
QT
758 }
759 if (strstr(line, "RECORD")) {
760 int lsb, msb, cnt;
761
c83b5ad9
QT
762 if (strlen(line) > 20) {
763 sscanf(line+17, "%x", &lsb);
764 sscanf(line+20, "%x", &msb);
765 cnt = lsb + msb * 256;
766 set_total_count(cnt, sess);
767 sess->count = 0;
768 }
b364d6bc
QT
769 }
770 if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
771 sess->count++;
772 set_current_count(sess->count, sess);
773 }
774 break;
775 case BABEL_DONE:
776 break;
777 default:
778 break;
779 }
780
781}
782
783static void gps_upload_progress_func(BabelProgressCode c, gpointer data, GpsSession * sess )
784{
785 gchar *line;
786 static int cnt = 0;
787
788 gdk_threads_enter ();
789 g_mutex_lock(sess->mutex);
790 if (!sess->ok) {
791 g_mutex_unlock(sess->mutex);
792 gps_session_delete(sess);
793 gdk_threads_leave();
794 g_thread_exit ( NULL );
795 }
796 g_mutex_unlock(sess->mutex);
797 gdk_threads_leave ();
798
799 switch(c) {
800 case BABEL_DIAG_OUTPUT:
801 line = (gchar *)data;
802
803 if (strstr(line, "PRDDAT")) {
804 gchar **tokens = g_strsplit(line, " ", 0);
805 gchar info[128];
806 int ilen = 0;
807 int i;
c83b5ad9
QT
808 int n_tokens = 0;
809
810 while (tokens[n_tokens])
811 n_tokens++;
812
813 if (n_tokens > 8) {
814 for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
815 guint ch;
816 sscanf(tokens[i], "%x", &ch);
817 info[ilen++] = ch;
818 }
819 info[ilen++] = 0;
820 set_gps_info(info, sess);
b364d6bc 821 }
c83b5ad9 822 g_strfreev(tokens);
b364d6bc
QT
823 }
824 if (strstr(line, "RECORD")) {
825 int lsb, msb;
826
c83b5ad9
QT
827 if (strlen(line) > 20) {
828 sscanf(line+17, "%x", &lsb);
829 sscanf(line+20, "%x", &msb);
830 cnt = lsb + msb * 256;
831 /* set_total_count(cnt, sess); */
832 sess->count = 0;
833 }
b364d6bc
QT
834 }
835 if ( strstr(line, "WPTDAT")) {
836 if (sess->count == 0) {
837 sess->progress_label = sess->wp_label;
838 set_total_count(cnt, sess);
839 }
840 sess->count++;
841 set_current_count(sess->count, sess);
842
843 }
844 if ( strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
845 if (sess->count == 0) {
846 sess->progress_label = sess->trk_label;
847 set_total_count(cnt, sess);
848 }
849 sess->count++;
850 set_current_count(sess->count, sess);
851 }
852 break;
853 case BABEL_DONE:
854 break;
855 default:
856 break;
857 }
858
859}
860
861static void gps_comm_thread(GpsSession *sess)
862{
863 gboolean result;
864
865 if (sess->direction == GPS_DOWN)
866 result = a_babel_convert_from (sess->vtl, sess->cmd_args,
867 (BabelStatusFunc) gps_download_progress_func, sess->port, sess);
868 else
869 result = a_babel_convert_to (sess->vtl, sess->cmd_args,
870 (BabelStatusFunc) gps_upload_progress_func, sess->port, sess);
871
872 gdk_threads_enter();
873 if (!result) {
874 gtk_label_set_text ( GTK_LABEL(sess->status_label), "Error: couldn't find gpsbabel." );
875 }
876 else {
877 g_mutex_lock(sess->mutex);
878 if (sess->ok) {
879 gtk_label_set_text ( GTK_LABEL(sess->status_label), "Done." );
880 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_ACCEPT, TRUE );
881 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog), GTK_RESPONSE_REJECT, FALSE );
882 } else {
883 /* canceled */
884 }
885 g_mutex_unlock(sess->mutex);
886 }
887
888 g_mutex_lock(sess->mutex);
889 if (sess->ok) {
890 sess->ok = FALSE;
891 g_mutex_unlock(sess->mutex);
892 }
893 else {
894 g_mutex_unlock(sess->mutex);
895 gps_session_delete(sess);
896 }
897 gdk_threads_leave();
898 g_thread_exit(NULL);
899}
900
901static gint gps_comm(VikTrwLayer *vtl, gps_dir dir, vik_gps_proto proto, gchar *port) {
902 GpsSession *sess = g_malloc(sizeof(GpsSession));
903
904 sess->mutex = g_mutex_new();
905 sess->direction = dir;
906 sess->vtl = vtl;
907 sess->port = g_strdup(port);
908 sess->ok = TRUE;
909 sess->cmd_args = g_strdup_printf("-D 9 -t -w -%c %s",
910 (dir == GPS_DOWN) ? 'i' : 'o', protocols_args[proto]);
911 sess->window_title = (dir == GPS_DOWN) ? "GPS Download" : "GPS Upload";
912
4a96999b 913 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 );
b364d6bc
QT
914 gtk_dialog_set_response_sensitive ( GTK_DIALOG(sess->dialog),
915 GTK_RESPONSE_ACCEPT, FALSE );
916 gtk_window_set_title ( GTK_WINDOW(sess->dialog), sess->window_title );
917
918 sess->status_label = gtk_label_new ("Status: detecting gpsbabel");
919 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(sess->dialog)->vbox),
920 sess->status_label, FALSE, FALSE, 5 );
921 gtk_widget_show_all(sess->status_label);
922
923 sess->gps_label = gtk_label_new ("GPS device: N/A");
924 sess->ver_label = gtk_label_new ("");
925 sess->id_label = gtk_label_new ("");
926 sess->wp_label = gtk_label_new ("");
927 sess->trk_label = gtk_label_new ("");
928
929 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(sess->dialog)->vbox), sess->gps_label, FALSE, FALSE, 5 );
930 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(sess->dialog)->vbox), sess->wp_label, FALSE, FALSE, 5 );
931 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(sess->dialog)->vbox), sess->trk_label, FALSE, FALSE, 5 );
932
933 gtk_widget_show_all(sess->dialog);
934
935 sess->progress_label = sess->wp_label;
936 sess->total_count = -1;
937
938 /* TODO: starting gps read/write thread here */
939 g_thread_create((GThreadFunc)gps_comm_thread, sess, FALSE, NULL );
940
941 gtk_dialog_run(GTK_DIALOG(sess->dialog));
942
943 gtk_widget_destroy(sess->dialog);
944
945 g_mutex_lock(sess->mutex);
946 if (sess->ok) {
947 sess->ok = FALSE; /* tell thread to stop */
948 g_mutex_unlock(sess->mutex);
949 }
950 else {
951 g_mutex_unlock(sess->mutex);
952 gps_session_delete(sess);
953 }
954
b364d6bc
QT
955 return 0;
956}
957
958static void gps_upload_cb( gpointer layer_and_vlp[2] )
959{
960 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
961 VikTrwLayer *vtl = vgl->trw_children[TRW_UPLOAD];
962 gps_comm(vtl, GPS_UP, vgl->protocol_id, params_ports[vgl->serial_port_id]);
963}
964
965static void gps_download_cb( gpointer layer_and_vlp[2] )
966{
967 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
968 VikTrwLayer *vtl = vgl->trw_children[TRW_DOWNLOAD];
969 gps_comm(vtl, GPS_DOWN, vgl->protocol_id, params_ports[vgl->serial_port_id]);
970}
700b0908
QT
971
972static void gps_empty_upload_cb( gpointer layer_and_vlp[2] )
973{
974 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
975 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
976 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
977}
978
979static void gps_empty_download_cb( gpointer layer_and_vlp[2] )
980{
981 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
982 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
983 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
984}
985
986static void gps_empty_all_cb( gpointer layer_and_vlp[2] )
987{
988 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
989 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_UPLOAD]);
990 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_UPLOAD]);
991 vik_trw_layer_delete_all_waypoints ( vgl-> trw_children[TRW_DOWNLOAD]);
992 vik_trw_layer_delete_all_tracks ( vgl-> trw_children[TRW_DOWNLOAD]);
993}
b87d3952 994
001a86db 995#ifdef VIK_CONFIG_REALTIME_GPS_TRACKING
b87d3952
QT
996static void realtime_tracking_draw(VikGpsLayer *vgl, VikViewport *vp)
997{
c4e61875 998 struct LatLon ll;
b87d3952
QT
999 VikCoord nw, se;
1000 struct LatLon lnw, lse;
1001 vik_viewport_screen_to_coord ( vp, -20, -20, &nw );
1002 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp)+20, vik_viewport_get_width(vp)+20, &se );
1003 vik_coord_to_latlon ( &nw, &lnw );
1004 vik_coord_to_latlon ( &se, &lse );
c4e61875
QT
1005 if ( vgl->realtime_fix.fix.latitude > lse.lat &&
1006 vgl->realtime_fix.fix.latitude < lnw.lat &&
1007 vgl->realtime_fix.fix.longitude > lnw.lon &&
1008 vgl->realtime_fix.fix.longitude < lse.lon ) {
b87d3952
QT
1009 VikCoord gps;
1010 gint x, y;
1011 gint half_back_x, half_back_y;
1012 gint half_back_bg_x, half_back_bg_y;
1013 gint pt_x, pt_y;
1014 gint ptbg_x, ptbg_y;
1015 gint side1_x, side1_y, side2_x, side2_y;
1016 gint side1bg_x, side1bg_y, side2bg_x, side2bg_y;
1017
c4e61875
QT
1018 ll.lat = vgl->realtime_fix.fix.latitude;
1019 ll.lon = vgl->realtime_fix.fix.longitude;
1020 vik_coord_load_from_latlon ( &gps, vik_viewport_get_coord_mode(vp), &ll);
b87d3952
QT
1021 vik_viewport_coord_to_screen ( vp, &gps, &x, &y );
1022
c4e61875
QT
1023 gdouble heading_cos = cos(M_PI/180*vgl->realtime_fix.fix.track);
1024 gdouble heading_sin = sin(M_PI/180*vgl->realtime_fix.fix.track);
b87d3952
QT
1025
1026 half_back_y = y+8*heading_cos;
1027 half_back_x = x-8*heading_sin;
1028 half_back_bg_y = y+10*heading_cos;
1029 half_back_bg_x = x-10*heading_sin;
1030
1031 pt_y = half_back_y-24*heading_cos;
1032 pt_x = half_back_x+24*heading_sin;
1033 ptbg_y = half_back_bg_y-28*heading_cos;
1034 ptbg_x = half_back_bg_x+28*heading_sin;
1035
1036 side1_y = half_back_y+9*heading_sin;
1037 side1_x = half_back_x+9*heading_cos;
1038 side1bg_y = half_back_bg_y+11*heading_sin;
1039 side1bg_x = half_back_bg_x+11*heading_cos;
1040
1041 side2_y = half_back_y-9*heading_sin;
1042 side2_x = half_back_x-9*heading_cos;
1043 side2bg_y = half_back_bg_y-11*heading_sin;
1044 side2bg_x = half_back_bg_x-11*heading_cos;
1045
1046 GdkPoint trian[3] = { { pt_x, pt_y }, {side1_x, side1_y}, {side2_x, side2_y} };
1047 GdkPoint trian_bg[3] = { { ptbg_x, pt_y }, {side1bg_x, side1bg_y}, {side2bg_x, side2bg_y} };
1048
1049 vik_viewport_draw_polygon ( vp, vgl->realtime_track_bg_gc, TRUE, trian_bg, 3 );
1050 vik_viewport_draw_polygon ( vp, vgl->realtime_track_gc, TRUE, trian, 3 );
c4e61875
QT
1051 vik_viewport_draw_rectangle ( vp,
1052 (vgl->realtime_fix.fix.mode > MODE_2D) ? vgl->realtime_track_pt2_gc : vgl->realtime_track_pt1_gc,
1053 TRUE, x-2, y-2, 4, 4 );
1054 //vgl->realtime_track_pt_gc = (vgl->realtime_track_pt_gc == vgl->realtime_track_pt1_gc) ? vgl->realtime_track_pt2_gc : vgl->realtime_track_pt1_gc;
b87d3952
QT
1055 }
1056}
1057
1058/* lock/unlock realtime_tracking_mutex when call this */
1059static void create_realtime_trackpoint(VikGpsLayer *vgl, gboolean forced)
1060{
c4e61875
QT
1061 struct LatLon ll;
1062 GList *last_tp;
97cab2d5
QT
1063
1064 /* Note that fix.time is a double, but it should not affect the precision
1065 for most GPS */
1066 time_t cur_timestamp = vgl->realtime_fix.fix.time;
1067 time_t last_timestamp = vgl->last_fix.fix.time;
1068
1069 if (cur_timestamp < last_timestamp) {
1070 return;
1071 }
1072
b87d3952 1073 if (vgl->realtime_record && vgl->realtime_fix.dirty) {
c4e61875
QT
1074 gboolean replace = FALSE;
1075 int heading = (int)floor(vgl->realtime_fix.fix.track);
1076 int last_heading = (int)floor(vgl->last_fix.fix.track);
1077 int alt = isnan(vgl->realtime_fix.fix.altitude) ? VIK_DEFAULT_ALTITUDE : floor(vgl->realtime_fix.fix.altitude);
1078 int last_alt = isnan(vgl->last_fix.fix.altitude) ? VIK_DEFAULT_ALTITUDE : floor(vgl->last_fix.fix.altitude);
1079 if (((last_tp = g_list_last(vgl->realtime_track->trackpoints)) != NULL) &&
1080 (vgl->realtime_fix.fix.mode > MODE_2D) &&
1081 (vgl->last_fix.fix.mode <= MODE_2D) &&
97cab2d5 1082 ((cur_timestamp - last_timestamp) < 2)) {
c4e61875
QT
1083 g_free(last_tp->data);
1084 vgl->realtime_track->trackpoints = g_list_delete_link(vgl->realtime_track->trackpoints, last_tp);
1085 replace = TRUE;
1086 }
97cab2d5
QT
1087 if (replace ||
1088 ((cur_timestamp != last_timestamp) &&
1089 ((forced ||
1090 ((heading < last_heading) && (heading < (last_heading - 3))) ||
1091 ((heading > last_heading) && (heading > (last_heading + 3))) ||
1092 ((alt != VIK_DEFAULT_ALTITUDE) && (alt != last_alt)))))) {
b87d3952
QT
1093 /* TODO: check for new segments */
1094 VikTrackpoint *tp = vik_trackpoint_new();
1095 tp->newsegment = FALSE;
b87d3952 1096 tp->has_timestamp = TRUE;
c4e61875 1097 tp->timestamp = vgl->realtime_fix.fix.time;
a2817d3c
QT
1098 tp->altitude = alt;
1099 /* speed only available for 3D fix. Check for NAN when use this speed */
1100 tp->speed = vgl->realtime_fix.fix.speed;
1101 tp->course = vgl->realtime_fix.fix.track;
1102 tp->nsats = vgl->realtime_fix.satellites_used;
1103 tp->fix_mode = vgl->realtime_fix.fix.mode;
1104 tp->extended = TRUE;
c4e61875
QT
1105
1106 ll.lat = vgl->realtime_fix.fix.latitude;
1107 ll.lon = vgl->realtime_fix.fix.longitude;
b87d3952 1108 vik_coord_load_from_latlon(&tp->coord,
c4e61875 1109 vik_trw_layer_get_coord_mode(vgl->trw_children[TRW_REALTIME]), &ll);
b87d3952
QT
1110
1111 vgl->realtime_track->trackpoints = g_list_append(vgl->realtime_track->trackpoints, tp);
1112 vgl->realtime_fix.dirty = FALSE;
a2817d3c 1113 vgl->realtime_fix.satellites_used = 0;
b87d3952
QT
1114 vgl->last_fix = vgl->realtime_fix;
1115 }
1116 }
1117
1118}
1119
1120void gpsd_raw_hook(VglGpsd *vgpsd, gchar *data)
1121{
c4e61875 1122 gboolean update_all = FALSE;
b87d3952
QT
1123 VikGpsLayer *vgl = vgpsd->vgl;
1124
c4e61875
QT
1125 if (!vgl->realtime_tracking) {
1126 g_warning("%s: receiving GPS data while not in realtime mode", __PRETTY_FUNCTION__);
b87d3952 1127 return;
b87d3952
QT
1128 }
1129
b87d3952
QT
1130 if ((vgpsd->gpsd.fix.mode >= MODE_2D) &&
1131 !isnan(vgpsd->gpsd.fix.latitude) &&
1132 !isnan(vgpsd->gpsd.fix.longitude) &&
1133 !isnan(vgpsd->gpsd.fix.track)) {
1134 g_mutex_lock(vgl->realtime_tracking_mutex);
c4e61875 1135 vgl->realtime_fix.fix = vgpsd->gpsd.fix;
a2817d3c 1136 vgl->realtime_fix.satellites_used = vgpsd->gpsd.satellites_used;
b87d3952
QT
1137 vgl->realtime_fix.dirty = TRUE;
1138
c4e61875
QT
1139 if (vgl->realtime_keep_at_center ||
1140 (vgl->realtime_jump_to_start && !vgl->realtime_track->trackpoints)) {
1141 struct LatLon ll;
1142 VikCoord center;
1143
1144 ll.lat = vgl->realtime_fix.fix.latitude;
1145 ll.lon = vgl->realtime_fix.fix.longitude;
1146 vik_coord_load_from_latlon(&center,
1147 vik_trw_layer_get_coord_mode(vgl->trw_children[TRW_REALTIME]), &ll);
1148 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vgl));
1149 VikViewport *vvp = vik_window_viewport(vw);
1150 vik_viewport_set_center_coord(vvp, &center);
1151 update_all = TRUE;
1152 }
1153
b87d3952
QT
1154 create_realtime_trackpoint(vgl, FALSE);
1155 g_mutex_unlock(vgl->realtime_tracking_mutex);
1156
c4e61875 1157 vik_layer_emit_update ( update_all ? VIK_LAYER(vgl) : VIK_LAYER(vgl->trw_children[TRW_REALTIME]));
b87d3952
QT
1158 }
1159}
1160
1161static gboolean gpsd_data_available(GIOChannel *source, GIOCondition condition, gpointer data)
1162{
b87d3952
QT
1163 VikGpsLayer *vgl = data;
1164 gps_poll(&vgl->vgpsd->gpsd);
1165 return TRUE;
1166}
1167
1168static gchar *make_track_name(VikTrwLayer *vtl)
1169{
1170 const gchar basename[] = "REALTIME";
1171 const gint bufsize = sizeof(basename) + 5;
1172 gchar *name = g_malloc(bufsize);
1173 strcpy(name, basename);
1174 gint i = 2;
1175
1176 while (vik_trw_layer_get_track(vtl, name) != NULL) {
1177 g_snprintf(name, bufsize, "%s#%d", basename, i);
1178 i++;
1179 }
1180 return(name);
1181
1182}
1183
1184static void gps_start_stop_tracking_cb( gpointer layer_and_vlp[2])
1185{
1186 VikGpsLayer *vgl = (VikGpsLayer *)layer_and_vlp[0];
1187 vgl->realtime_tracking = (vgl->realtime_tracking == FALSE);
1188
a2817d3c
QT
1189 /* Make sure we are still in the boat with libgps */
1190 g_assert((VIK_GPS_MODE_2D == MODE_2D) && (VIK_GPS_MODE_3D == MODE_3D));
1191
b87d3952
QT
1192 if (vgl->realtime_tracking) {
1193 struct gps_data_t *gpsd = gps_open(vgl->gpsd_host, vgl->gpsd_port);
1194 if (gpsd == NULL) {
4863105b
QT
1195 GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER(vgl),
1196 GTK_DIALOG_DESTROY_WITH_PARENT,
1197 GTK_MESSAGE_ERROR,
1198 GTK_BUTTONS_CLOSE,
1199 "Failed to connect to gpsd at %s (port %s)",
1200 vgl->gpsd_host, vgl->gpsd_port);
1201 gtk_dialog_run (GTK_DIALOG (dialog));
1202 gtk_widget_destroy (dialog);
1203
b87d3952
QT
1204 vgl->realtime_tracking = FALSE;
1205 return;
1206 }
1207 vgl->vgpsd = g_realloc(gpsd, sizeof(VglGpsd));
1208 vgl->vgpsd->vgl = vgl;
b87d3952 1209
c4e61875
QT
1210 vgl->realtime_fix.dirty = vgl->last_fix.dirty = FALSE;
1211 /* track alt/time graph uses VIK_DEFAULT_ALTITUDE (0.0) as invalid */
1212 vgl->realtime_fix.fix.altitude = vgl->last_fix.fix.altitude = VIK_DEFAULT_ALTITUDE;
1213 vgl->realtime_fix.fix.speed = vgl->last_fix.fix.speed = NAN;
b87d3952 1214
b87d3952 1215 if (vgl->realtime_record) {
c4e61875 1216 VikTrwLayer *vtl = vgl->trw_children[TRW_REALTIME];
b87d3952
QT
1217 vgl->realtime_track = vik_track_new();
1218 vgl->realtime_track->visible = TRUE;
1219 vgl->realtime_track_name = make_track_name(vtl);
1220 vik_trw_layer_add_track(vtl, vgl->realtime_track_name, vgl->realtime_track);
1221 }
1222
c4e61875
QT
1223 gps_set_raw_hook(&vgl->vgpsd->gpsd, gpsd_raw_hook);
1224 vgl->realtime_io_channel = g_io_channel_unix_new(vgl->vgpsd->gpsd.gps_fd);
1225 vgl->realtime_io_watch_id = g_io_add_watch( vgl->realtime_io_channel,
1226 G_IO_IN, gpsd_data_available, vgl);
1227
b87d3952
QT
1228 gps_query(&vgl->vgpsd->gpsd, "w+x");
1229
1230 }
1231 else { /* stop realtime tracking */
1232 /* TODO: handle race condition here , make sure vgpsd is NULL */
1233 g_mutex_lock(vgl->realtime_tracking_mutex);
1234 gps_close(&vgl->vgpsd->gpsd);
1235 vgl->vgpsd = NULL;
1236 // g_source_remove(vgl->realtime_timeout);
1237 g_source_remove(vgl->realtime_io_watch_id);
1238 g_io_channel_unref (vgl->realtime_io_channel);
1239
1240 if (vgl->realtime_record) {
1241 create_realtime_trackpoint(vgl, TRUE);
1242 if ((vgl->realtime_track->trackpoints == NULL) || (vgl->realtime_track->trackpoints->next == NULL))
c4e61875 1243 vik_trw_layer_delete_track(vgl->trw_children[TRW_REALTIME], vgl->realtime_track_name);
b87d3952
QT
1244 }
1245 g_mutex_unlock(vgl->realtime_tracking_mutex);
1246 }
1247}
001a86db 1248#endif /* VIK_CONFIG_REALTIME_GPS_TRACKING */
b87d3952 1249