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