1 /* fso-gpsd - a gpsd compatibility daemon for the FSO frameworkd
3 * Copyright (C) 2008 Sascha Wessel <wessel@nefkom.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/types.h>
33 #include <dbus/dbus-glib.h>
34 #include <glib-object.h>
37 #define KNOTS_TO_KPH (1.852)
38 #define KNOTS_TO_MPS (0.51444444)
40 /******************************************************************************/
44 g_log(NULL, G_LOG_LEVEL_ERROR, __VA_ARGS__); \
48 #define CRITICAL(...) \
50 if (log_level & G_LOG_LEVEL_CRITICAL) { \
51 g_log(NULL, G_LOG_LEVEL_CRITICAL, __VA_ARGS__); \
55 #define WARNING(...) \
57 if (log_level & G_LOG_LEVEL_WARNING) { \
58 g_log(NULL, G_LOG_LEVEL_WARNING, __VA_ARGS__); \
62 #define MESSAGE(...) \
64 if (log_level & G_LOG_LEVEL_MESSAGE) { \
65 g_log(NULL, G_LOG_LEVEL_MESSAGE, __VA_ARGS__); \
71 if (log_level & G_LOG_LEVEL_INFO) { \
72 g_log(NULL, G_LOG_LEVEL_INFO, __VA_ARGS__); \
78 if (log_level & G_LOG_LEVEL_DEBUG) { \
79 g_log(NULL, G_LOG_LEVEL_DEBUG, __VA_ARGS__); \
83 /******************************************************************************/
85 #define POSITION_LATITUDE_IS_VALID (position_fields & (1 << 0))
86 #define POSITION_LONGITUDE_IS_VALID (position_fields & (1 << 1))
87 #define POSITION_ALTITUDE_IS_VALID (position_fields & (1 << 2))
89 #define ACCURACY_PDOP_IS_VALID (accuracy_fields & (1 << 0))
90 #define ACCURACY_HDOP_IS_VALID (accuracy_fields & (1 << 1))
91 #define ACCURACY_VDOP_IS_VALID (accuracy_fields & (1 << 2))
93 #define COURSE_SPEED_IS_VALID (course_fields & (1 << 0))
94 #define COURSE_DIRECTION_IS_VALID (course_fields & (1 << 1))
95 #define COURSE_CLIMB_IS_VALID (course_fields & (1 << 2))
97 /******************************************************************************/
113 /******************************************************************************/
115 static int log_level
= G_LOG_LEVEL_ERROR
116 | G_LOG_LEVEL_CRITICAL
117 | G_LOG_LEVEL_WARNING
;
119 static gboolean background
= FALSE
;
120 static gboolean nowait
= FALSE
;
122 /******************************************************************************/
124 static gboolean info_queued
= FALSE
;
125 static gboolean sats_queued
= FALSE
;
126 static gboolean nmea_queued
= FALSE
;
128 /******************************************************************************/
130 static unsigned timeout_handler_registered
= FALSE
;
132 /******************************************************************************/
134 static GList
*client_list
= NULL
;
136 /******************************************************************************/
138 static DBusGConnection
*connection
= NULL
;
140 /******************************************************************************/
142 static const char *gypsy_device
= "";
143 static const char *gypsy_service
= "org.freedesktop.Gypsy";
144 static const char *gypsy_server_path
= "/org/freedesktop/Gypsy";
145 static char *gypsy_device_path
= NULL
;
147 static gboolean gypsy_device_create_failed
= FALSE
;
148 static gboolean gypsy_device_start_failed
= FALSE
;
150 /******************************************************************************/
152 #define GYPSY_SERVER "org.freedesktop.Gypsy.Server"
153 static DBusGProxy
*server_proxy
= NULL
;
155 #define GYPSY_DEVICE "org.freedesktop.Gypsy.Device"
156 static DBusGProxy
*device_proxy
= NULL
;
157 static gboolean device_connectionstatus
= 0;
158 static int device_fixstatus
= 0; /* 0=INVALID, 1=NONE, 2=2D, 3=3D */
160 #define GYPSY_TIME "org.freedesktop.Gypsy.Time"
161 static DBusGProxy
*time_proxy
= NULL
;
162 static int time_seconds
= 0;
164 #define GYPSY_POSITION "org.freedesktop.Gypsy.Position"
165 static DBusGProxy
*position_proxy
= NULL
;
166 static int position_fields
= 0;
167 static int position_timestamp
= 0;
168 static double position_latitude
= 0.0;
169 static double position_longitude
= 0.0;
170 static double position_altitude
= 0.0;
172 #define GYPSY_ACCURACY "org.freedesktop.Gypsy.Accuracy"
173 static DBusGProxy
*accuracy_proxy
= NULL
;
174 static int accuracy_fields
= 0;
175 static double accuracy_pdop
= 0.0;
176 static double accuracy_hdop
= 0.0;
177 static double accuracy_vdop
= 0.0;
179 #define GYPSY_COURSE "org.freedesktop.Gypsy.Course"
180 static DBusGProxy
*course_proxy
= NULL
;
181 static int course_fields
= 0;
182 static int course_timestamp
= 0;
183 static double course_speed
= 0.0;
184 static double course_direction
= 0.0;
185 static double course_climb
= 0.0;
187 #define GYPSY_SATELLITE "org.freedesktop.Gypsy.Satellite"
188 static DBusGProxy
*satellite_proxy
= NULL
;
189 #define SATELLITEC_MAX 12
190 static struct satellite satellite_satellitev
[SATELLITEC_MAX
];
191 static unsigned satellite_satellitec
= 0;
193 /******************************************************************************/
195 static GString
*nmea_gga
;
196 static GString
*nmea_gsa
;
197 static GString
*nmea_gsv
[3];
198 static GString
*nmea_rmc
;
199 static GString
*nmea_gll
;
200 static GString
*nmea_vtg
;
202 /******************************************************************************/
207 if (POSITION_LATITUDE_IS_VALID
&& POSITION_LONGITUDE_IS_VALID
) {
208 if (POSITION_ALTITUDE_IS_VALID
) {
209 return MIN(device_fixstatus
, 3);
211 return MIN(device_fixstatus
, 2);
214 return MIN(device_fixstatus
, 1);
219 check_period(const GTimeVal
*tv1
, const GTimeVal
*tv2
, glong sec
)
221 glong tv1_sec
= tv1
->tv_sec
+ sec
;
222 glong tv1_usec
= tv1
->tv_usec
;
223 glong tv2_sec
= tv2
->tv_sec
;
224 glong tv2_usec
= tv2
->tv_usec
;
226 if (tv1_sec
== tv2_sec
) {
227 return (tv1_usec
> tv2_usec
);
229 return (tv1_sec
> tv2_sec
);
233 /******************************************************************************/
236 shutdown_client(struct client
*client
)
238 if (client
->channel
) {
239 MESSAGE("Shutdown client");
241 g_io_channel_shutdown(client
->channel
, FALSE
, NULL
);
244 client
->channel
= NULL
;
245 client
->watcher
= FALSE
;
250 send_to_client(struct client
*client
, const char *string
, gsize len
)
255 if (!client
->channel
) {
259 status
= g_io_channel_write_chars(client
->channel
, string
,
260 len
, &bytes_written
, NULL
);
262 if ((bytes_written
!= len
) || (status
!= G_IO_STATUS_NORMAL
)) {
263 shutdown_client(client
);
267 /******************************************************************************/
270 add_nmea_checksum(GString
*nmea
)
282 checksum
^= (int) *p
;
286 g_string_append_printf(nmea
, "*%02x", checksum
);
290 add_nmea_time(GString
*nmea
)
292 if (time_seconds
<= 0) {
293 g_string_append_c(nmea
, ',');
298 seconds
= time_seconds
;
299 tm
= gmtime(&seconds
);
301 g_string_append_printf(nmea
, ",%02d%02d%02d.00",
302 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
307 add_nmea_latitude(GString
*nmea
)
309 if (!POSITION_LATITUDE_IS_VALID
) {
310 g_string_append_c(nmea
, ',');
311 g_string_append_c(nmea
, ',');
315 a
= fabs(position_latitude
);
318 g_string_append_printf(nmea
, ",%010.5f,%c",
319 (d
* 100.0) + ((a
- d
) * 60.0),
320 (position_latitude
> 0) ? 'N' : 'S');
325 add_nmea_longitude(GString
*nmea
)
327 if (!POSITION_LONGITUDE_IS_VALID
) {
328 g_string_append_c(nmea
, ',');
329 g_string_append_c(nmea
, ',');
333 a
= fabs(position_longitude
);
336 g_string_append_printf(nmea
, ",%011.5f,%c",
337 (d
* 100.0) + ((a
- d
) * 60.0),
338 (position_longitude
> 0) ? 'E' : 'W');
342 /******************************************************************************/
345 update_nmea_gga(void)
349 g_string_assign(nmea_gga
, "$GPGGA");
351 add_nmea_time(nmea_gga
);
353 add_nmea_latitude(nmea_gga
);
355 add_nmea_longitude(nmea_gga
);
357 g_string_append_printf(nmea_gga
, ",%1d", MAX(get_fixstatus() - 1, 0));
359 for (i
= 0, used
= 0; i
< satellite_satellitec
; i
++) {
360 if (satellite_satellitev
[i
].used
) {
365 g_string_append_printf(nmea_gga
, ",%02d", used
);
367 if (!ACCURACY_HDOP_IS_VALID
) {
368 g_string_append_c(nmea_gga
, ',');
370 g_string_append_printf(nmea_gga
, ",%04.2f", accuracy_hdop
);
373 if (!POSITION_ALTITUDE_IS_VALID
) {
374 g_string_append_c(nmea_gga
, ',');
375 g_string_append_c(nmea_gga
, ',');
377 g_string_append_printf(nmea_gga
, ",%03.1f,M",
381 g_string_append_c(nmea_gga
, ','); /* FIXME */
382 g_string_append_c(nmea_gga
, ',');
383 g_string_append_c(nmea_gga
, ',');
384 g_string_append_c(nmea_gga
, ',');
386 add_nmea_checksum(nmea_gga
);
390 update_nmea_gsa(void)
394 g_string_assign(nmea_gsa
, "$GPGSA");
396 g_string_append_c(nmea_gsa
, ',');
397 g_string_append_c(nmea_gsa
, 'A');
399 g_string_append_printf(nmea_gsa
, ",%1d", MAX(get_fixstatus() - 1, 0));
401 for (i
= 0; i
< 12; i
++) {
402 if (i
< satellite_satellitec
) {
403 g_string_append_printf(nmea_gsa
, ",%02d",
404 satellite_satellitev
[i
].prn
);
406 g_string_append_c(nmea_gsa
, ',');
410 if (!ACCURACY_PDOP_IS_VALID
) {
411 g_string_append_c(nmea_gsa
, ',');
413 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_pdop
);
416 if (!ACCURACY_HDOP_IS_VALID
) {
417 g_string_append_c(nmea_gsa
, ',');
419 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_hdop
);
422 if (!ACCURACY_VDOP_IS_VALID
) {
423 g_string_append_c(nmea_gsa
, ',');
425 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_vdop
);
428 add_nmea_checksum(nmea_gsa
);
432 update_nmea_gsv(void)
436 unsigned sentence_count
;
438 g_string_truncate(nmea_gsv
[0], 0);
439 g_string_truncate(nmea_gsv
[1], 0);
440 g_string_truncate(nmea_gsv
[2], 0);
442 if (satellite_satellitec
== 0) {
443 g_string_assign(nmea_gsv
[0], "$GPGSV,1,1,00*79");
447 sat_count
= MIN(satellite_satellitec
, 12);
448 sentence_count
= ((sat_count
- 1) / 4) + 1;
450 for (i
= 0; i
< sat_count
; i
++) {
451 int index_div
, index_mod
;
456 if (index_mod
== 0) {
457 g_string_append_printf(nmea_gsv
[index_div
],
458 "$GPGSV,%1d,%1d,%02d",
464 g_string_append_printf(nmea_gsv
[index_div
],
465 ",%02u,%02u,%03u,%02u",
466 satellite_satellitev
[i
].prn
,
467 satellite_satellitev
[i
].elevation
,
468 satellite_satellitev
[i
].azimuth
,
469 satellite_satellitev
[i
].snr
);
472 for (i
= 0; i
< 3; i
++) {
473 if (nmea_gsv
[i
]->len
> 0) {
474 add_nmea_checksum(nmea_gsv
[i
]);
480 update_nmea_rmc(void)
482 g_string_assign(nmea_rmc
, "$GPRMC");
484 add_nmea_time(nmea_rmc
);
486 if (get_fixstatus() > 1) {
487 g_string_append_c(nmea_rmc
, ',');
488 g_string_append_c(nmea_rmc
, 'A');
490 g_string_append_c(nmea_rmc
, ',');
491 g_string_append_c(nmea_rmc
, 'V');
494 add_nmea_latitude(nmea_rmc
);
496 add_nmea_longitude(nmea_rmc
);
498 if (!COURSE_SPEED_IS_VALID
) {
499 g_string_append_c(nmea_rmc
, ',');
501 g_string_append_printf(nmea_rmc
, ",%07.3f",
505 if (!COURSE_DIRECTION_IS_VALID
) {
506 g_string_append_c(nmea_rmc
, ',');
508 g_string_append_printf(nmea_rmc
, ",%06.2f",
512 if (time_seconds
<= 0) {
513 g_string_append_c(nmea_rmc
, ',');
518 seconds
= time_seconds
;
519 tm
= gmtime(&seconds
);
521 g_string_append_printf(nmea_rmc
, ",%02d%02d%02d",
522 tm
->tm_mday
, tm
->tm_mon
+ 1, tm
->tm_year
% 100);
525 g_string_append_c(nmea_rmc
, ',');
526 g_string_append_c(nmea_rmc
, ',');
528 add_nmea_checksum(nmea_rmc
);
532 update_nmea_gll(void)
534 g_string_assign(nmea_gll
, "$GPGLL");
536 add_nmea_latitude(nmea_gll
);
538 add_nmea_longitude(nmea_gll
);
540 add_nmea_time(nmea_gll
);
542 if (get_fixstatus() > 1) {
543 g_string_append_c(nmea_gll
, ',');
544 g_string_append_c(nmea_gll
, 'A');
546 g_string_append_c(nmea_gll
, ',');
547 g_string_append_c(nmea_gll
, 'V');
550 add_nmea_checksum(nmea_gll
);
554 update_nmea_vtg(void)
556 g_string_assign(nmea_vtg
, "$GPVTG");
558 if (!COURSE_DIRECTION_IS_VALID
) {
559 g_string_append_c(nmea_vtg
, ',');
560 g_string_append_c(nmea_vtg
, ',');
562 g_string_append_printf(nmea_vtg
, ",%04.2f,T", course_direction
);
565 g_string_append_c(nmea_vtg
, ','); /* FIXME */
566 g_string_append_c(nmea_vtg
, ',');
568 if (!COURSE_SPEED_IS_VALID
) {
569 g_string_append_c(nmea_vtg
, ',');
570 g_string_append_c(nmea_vtg
, ',');
571 g_string_append_c(nmea_vtg
, ',');
572 g_string_append_c(nmea_vtg
, ',');
574 g_string_append_printf(nmea_vtg
, ",%05.3f,N,%05.3f,K",
575 course_speed
, course_speed
* KNOTS_TO_KPH
);
578 add_nmea_checksum(nmea_vtg
);
581 /******************************************************************************/
584 send_nmea_to_clients(gpointer data
)
589 for (string
= NULL
, l
= client_list
; l
; l
= l
->next
) {
590 struct client
*client
= l
->data
;
594 static GTimeVal timestamp
= { 0, 0 };
596 if (data
&& check_period(×tamp
, data
, 1)) {
600 g_get_current_time(×tamp
);
602 string
= g_string_sized_new(1024);
604 if (!nmea_gga
->len
) {
607 if (!nmea_gsa
->len
) {
610 if (!nmea_gsv
[0]->len
) {
613 if (!nmea_rmc
->len
) {
616 if (!nmea_gll
->len
) {
619 if (!nmea_vtg
->len
) {
624 INFO("Sending nmea: %s",
626 g_string_append_len(string
,
629 g_string_append_c(string
, '\r');
630 g_string_append_c(string
, '\n');
633 INFO("Sending nmea: %s",
635 g_string_append_len(string
,
638 g_string_append_c(string
, '\r');
639 g_string_append_c(string
, '\n');
641 if (nmea_gsv
[0]->len
) {
642 INFO("Sending nmea: %s",
644 g_string_append_len(string
,
647 g_string_append_c(string
, '\r');
648 g_string_append_c(string
, '\n');
650 if (nmea_gsv
[1]->len
) {
651 INFO("Sending nmea: %s",
653 g_string_append_len(string
,
656 g_string_append_c(string
, '\r');
657 g_string_append_c(string
, '\n');
659 if (nmea_gsv
[2]->len
) {
660 INFO("Sending nmea: %s",
662 g_string_append_len(string
,
665 g_string_append_c(string
, '\r');
666 g_string_append_c(string
, '\n');
669 INFO("Sending nmea: %s",
671 g_string_append_len(string
,
674 g_string_append_c(string
, '\r');
675 g_string_append_c(string
, '\n');
678 INFO("Sending nmea: %s",
680 g_string_append_len(string
,
683 g_string_append_c(string
, '\r');
684 g_string_append_c(string
, '\n');
687 INFO("Sending nmea: %s",
689 g_string_append_len(string
,
692 g_string_append_c(string
, '\r');
693 g_string_append_c(string
, '\n');
697 send_to_client(client
, string
->str
, string
->len
);
702 g_string_free(string
, TRUE
);
711 queue_send_nmea_to_clients(void)
719 g_idle_add(send_nmea_to_clients
, NULL
);
722 /******************************************************************************/
725 add_sats(GString
*string
)
729 if (satellite_satellitec
== 0) {
730 g_string_append(string
, ",Y=?");
734 g_string_append(string
, ",Y=-");
736 if (time_seconds
<= 0) {
737 g_string_append(string
, " ? ");
739 g_string_append_printf(string
, " %d.000 ", time_seconds
);
742 count
= MIN(satellite_satellitec
, 12);
744 g_string_append_printf(string
, "%d:", count
);
746 for (i
= 0; i
< count
; i
++) {
747 g_string_append_printf(string
, "%d %d %d %d %d:",
748 satellite_satellitev
[i
].prn
,
749 satellite_satellitev
[i
].elevation
,
750 satellite_satellitev
[i
].azimuth
,
751 satellite_satellitev
[i
].snr
,
752 satellite_satellitev
[i
].used
);
756 /******************************************************************************/
759 send_sats_to_clients(gpointer data
)
764 for (string
= NULL
, l
= client_list
; l
; l
= l
->next
) {
765 struct client
*client
= l
->data
;
767 if (client
->watcher
) {
769 static GTimeVal timestamp
= { 0, 0 };
771 if (data
&& check_period(×tamp
, data
, 1)) {
775 g_get_current_time(×tamp
);
777 string
= g_string_sized_new(1024);
779 g_string_append(string
, "GPSD");
783 INFO("Sending sats: %s", string
->str
);
785 g_string_append_c(string
, '\r');
786 g_string_append_c(string
, '\n');
789 send_to_client(client
, string
->str
, string
->len
);
794 g_string_free(string
, TRUE
);
803 queue_send_sats_to_clients(void)
811 g_idle_add(send_sats_to_clients
, NULL
);
814 /******************************************************************************/
817 add_info(GString
*string
)
819 if (!device_connectionstatus
|| get_fixstatus() <= 1) {
820 g_string_append(string
, ",O=?");
824 g_string_append(string
, ",O=-");
826 if (time_seconds
<= 0) {
827 g_string_append_c(string
, ' ');
828 g_string_append_c(string
, '?');
830 g_string_append_printf(string
, " %d.000", time_seconds
);
833 g_string_append_c(string
, ' '); /* FIXME */
834 g_string_append_c(string
, '?');
836 if (!POSITION_LATITUDE_IS_VALID
) {
837 g_string_append_c(string
, ' ');
838 g_string_append_c(string
, '?');
840 g_string_append_printf(string
, " %.6f", position_latitude
);
842 if (!POSITION_LONGITUDE_IS_VALID
) {
843 g_string_append_c(string
, ' ');
844 g_string_append_c(string
, '?');
846 g_string_append_printf(string
, " %.6f", position_longitude
);
848 if (!POSITION_ALTITUDE_IS_VALID
) {
849 g_string_append_c(string
, ' ');
850 g_string_append_c(string
, '?');
852 g_string_append_printf(string
, " %.2f", position_altitude
);
854 if (!ACCURACY_HDOP_IS_VALID
) {
855 g_string_append_c(string
, ' ');
856 g_string_append_c(string
, '?');
858 g_string_append_printf(string
, " %.2f", accuracy_hdop
);
860 if (!ACCURACY_VDOP_IS_VALID
) {
861 g_string_append_c(string
, ' ');
862 g_string_append_c(string
, '?');
864 g_string_append_printf(string
, " %.2f", accuracy_vdop
);
866 if (!COURSE_DIRECTION_IS_VALID
) {
867 g_string_append_c(string
, ' ');
868 g_string_append_c(string
, '?');
870 g_string_append_printf(string
, " %.4f", course_direction
);
872 if (!COURSE_SPEED_IS_VALID
) {
873 g_string_append_c(string
, ' ');
874 g_string_append_c(string
, '?');
876 g_string_append_printf(string
, " %.3f",
877 course_speed
* KNOTS_TO_MPS
);
879 if (!COURSE_CLIMB_IS_VALID
) {
880 g_string_append_c(string
, ' ');
881 g_string_append_c(string
, '?');
883 g_string_append_printf(string
, " %.3f", course_climb
);
886 g_string_append(string
, " ? ? ?"); /* FIXME */
888 g_string_append_printf(string
, " %d", get_fixstatus());
891 /******************************************************************************/
894 send_info_to_clients(gpointer data
)
899 for (string
= NULL
, l
= client_list
; l
; l
= l
->next
) {
900 struct client
*client
= l
->data
;
902 if (client
->watcher
) {
904 static GTimeVal timestamp
= { 0, 0 };
906 if (data
&& check_period(×tamp
, data
, 1)) {
910 g_get_current_time(×tamp
);
912 string
= g_string_sized_new(1024);
914 g_string_append(string
, "GPSD");
918 INFO("Sending info: %s", string
->str
);
920 g_string_append_c(string
, '\r');
921 g_string_append_c(string
, '\n');
924 send_to_client(client
, string
->str
, string
->len
);
929 g_string_free(string
, TRUE
);
938 queue_send_info_to_clients(void)
946 g_idle_add(send_info_to_clients
, NULL
);
949 /******************************************************************************/
952 connection_status_changed(
954 gboolean connectionstatus
,
958 device_connectionstatus
= connectionstatus
;
960 INFO(GYPSY_DEVICE
": ConnectionStatusChanged(connectionstatus=%s)",
961 device_connectionstatus
? "TRUE" : "FALSE");
973 device_fixstatus
= fixstatus
;
975 switch (device_fixstatus
) {
990 INFO(GYPSY_DEVICE
": FixStatusChanged(fixstatus=%s)", str
);
992 g_string_truncate(nmea_gga
, 0);
993 g_string_truncate(nmea_gsa
, 0);
994 g_string_truncate(nmea_rmc
, 0);
995 g_string_truncate(nmea_gll
, 0);
997 queue_send_nmea_to_clients();
998 queue_send_info_to_clients();
1008 time_seconds
= seconds
;
1010 INFO(GYPSY_TIME
": TimeChanged(seconds=%d)", time_seconds
);
1012 g_string_truncate(nmea_gga
, 0);
1013 g_string_truncate(nmea_rmc
, 0);
1014 g_string_truncate(nmea_gll
, 0);
1016 queue_send_nmea_to_clients();
1017 queue_send_info_to_clients();
1031 position_fields
= fields
;
1032 position_timestamp
= timestamp
;
1033 position_latitude
= latitude
;
1034 position_longitude
= longitude
;
1035 position_altitude
= altitude
;
1037 INFO(GYPSY_POSITION
": PositionChanged(timestamp=%d, latitude=%f, longitude=%f, altitude=%f)",
1039 POSITION_LATITUDE_IS_VALID
? position_latitude
: NAN
,
1040 POSITION_LONGITUDE_IS_VALID
? position_longitude
: NAN
,
1041 POSITION_ALTITUDE_IS_VALID
? position_altitude
: NAN
);
1043 g_string_truncate(nmea_gga
, 0);
1044 g_string_truncate(nmea_rmc
, 0);
1045 g_string_truncate(nmea_gll
, 0);
1047 queue_send_nmea_to_clients();
1048 queue_send_info_to_clients();
1061 accuracy_fields
= fields
;
1062 accuracy_pdop
= pdop
;
1063 accuracy_hdop
= hdop
;
1064 accuracy_vdop
= vdop
;
1066 INFO(GYPSY_ACCURACY
": AccuracyChanged(pdop=%f, hdop=%f, vdop=%f)",
1067 ACCURACY_PDOP_IS_VALID
? accuracy_pdop
: NAN
,
1068 ACCURACY_HDOP_IS_VALID
? accuracy_hdop
: NAN
,
1069 ACCURACY_VDOP_IS_VALID
? accuracy_vdop
: NAN
);
1071 g_string_truncate(nmea_gga
, 0);
1072 g_string_truncate(nmea_gsa
, 0);
1074 queue_send_nmea_to_clients();
1075 queue_send_info_to_clients();
1089 course_fields
= fields
;
1090 course_timestamp
= timestamp
;
1091 course_speed
= speed
;
1092 course_direction
= direction
;
1093 course_climb
= climb
;
1095 INFO(GYPSY_COURSE
": CourseChanged(timestamp=%d, speed=%f, direction=%f, climb=%f)",
1097 COURSE_SPEED_IS_VALID
? course_speed
: NAN
,
1098 COURSE_DIRECTION_IS_VALID
? course_direction
: NAN
,
1099 COURSE_CLIMB_IS_VALID
? course_climb
: NAN
);
1101 g_string_truncate(nmea_rmc
, 0);
1102 g_string_truncate(nmea_vtg
, 0);
1104 queue_send_nmea_to_clients();
1105 queue_send_info_to_clients();
1111 GPtrArray
*satellites
,
1118 satellite_satellitec
= 0;
1120 satellite_satellitec
= MIN(SATELLITEC_MAX
, satellites
->len
);
1123 for (i
= 0; i
< satellite_satellitec
; i
++) {
1124 struct satellite
*sat
;
1127 sat
= satellite_satellitev
+ i
;
1128 val
= satellites
->pdata
[i
];
1130 sat
->prn
= g_value_get_uint(g_value_array_get_nth(val
, 0));
1131 sat
->used
= g_value_get_boolean(g_value_array_get_nth(val
, 1));
1132 sat
->elevation
= g_value_get_uint(g_value_array_get_nth(val
, 2));
1133 sat
->azimuth
= g_value_get_uint(g_value_array_get_nth(val
, 3));
1134 sat
->snr
= g_value_get_uint(g_value_array_get_nth(val
, 4));
1136 INFO(GYPSY_SATELLITE
": SatellitesChanged(index=%d, prn=%u, used=%s, elevation=%u, azimuth=%u, snr=%u)",
1139 sat
->used
? "TRUE" : "FALSE",
1145 g_string_truncate(nmea_gga
, 0);
1146 g_string_truncate(nmea_gsa
, 0);
1147 g_string_truncate(nmea_gsv
[0], 0);
1148 g_string_truncate(nmea_gsv
[1], 0);
1149 g_string_truncate(nmea_gsv
[2], 0);
1151 queue_send_nmea_to_clients();
1152 queue_send_sats_to_clients();
1155 /******************************************************************************/
1158 get_connection_status_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1160 GError
*error
= NULL
;
1161 gboolean connectionstatus
= FALSE
;
1163 DEBUG(GYPSY_DEVICE
": GetConnectionStatus: Notify");
1165 dbus_g_proxy_end_call(proxy
, call
, &error
,
1166 G_TYPE_BOOLEAN
, &connectionstatus
,
1170 WARNING(GYPSY_DEVICE
": GetConnectionStatus: %s", error
->message
);
1171 g_error_free(error
);
1173 DEBUG(GYPSY_DEVICE
": GetConnectionStatus: OK");
1174 connection_status_changed(NULL
, connectionstatus
, NULL
);
1179 get_fix_status_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1181 GError
*error
= NULL
;
1184 DEBUG(GYPSY_DEVICE
": GetFixStatus: Notify");
1186 dbus_g_proxy_end_call(proxy
, call
, &error
,
1187 G_TYPE_INT
, &fixstatus
,
1191 WARNING(GYPSY_DEVICE
": GetFixStatus: %s", error
->message
);
1192 g_error_free(error
);
1194 DEBUG(GYPSY_DEVICE
": GetFixStatus: OK");
1195 fix_status_changed(NULL
, fixstatus
, NULL
);
1200 get_time_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1202 GError
*error
= NULL
;
1205 DEBUG(GYPSY_TIME
": GetTime: Notify");
1207 dbus_g_proxy_end_call(proxy
, call
, &error
,
1208 G_TYPE_INT
, &seconds
,
1212 WARNING(GYPSY_TIME
": GetTime: %s", error
->message
);
1213 g_error_free(error
);
1215 DEBUG(GYPSY_TIME
": GetTime: OK");
1216 time_changed(NULL
, seconds
, NULL
);
1221 get_position_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1223 GError
*error
= NULL
;
1224 int fields
= 0, timestamp
= 0;
1225 double latitude
= 0.0, longitude
= 0.0, altitude
= 0.0;
1227 DEBUG(GYPSY_POSITION
": GetPosition: Notify");
1229 dbus_g_proxy_end_call(proxy
, call
, &error
,
1230 G_TYPE_INT
, &fields
,
1231 G_TYPE_INT
, ×tamp
,
1232 G_TYPE_DOUBLE
, &latitude
,
1233 G_TYPE_DOUBLE
, &longitude
,
1234 G_TYPE_DOUBLE
, &altitude
,
1238 WARNING(GYPSY_POSITION
": GetPosition: %s", error
->message
);
1239 g_error_free(error
);
1241 DEBUG(GYPSY_POSITION
": GetPosition: OK");
1242 position_changed(NULL
, fields
, timestamp
, latitude
, longitude
,
1248 get_accuracy_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1250 GError
*error
= NULL
;
1252 double pdop
= 0.0, hdop
= 0.0, vdop
= 0.0;
1254 DEBUG(GYPSY_ACCURACY
": GetAccuracy: Notify");
1256 dbus_g_proxy_end_call(proxy
, call
, &error
,
1257 G_TYPE_INT
, &fields
,
1258 G_TYPE_DOUBLE
, &pdop
,
1259 G_TYPE_DOUBLE
, &hdop
,
1260 G_TYPE_DOUBLE
, &vdop
,
1264 WARNING(GYPSY_ACCURACY
": GetAccuracy: %s", error
->message
);
1265 g_error_free(error
);
1267 DEBUG(GYPSY_ACCURACY
": GetAccuracy: OK");
1268 accuracy_changed(NULL
, fields
, pdop
, hdop
, vdop
, NULL
);
1273 get_course_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1275 GError
*error
= NULL
;
1276 int fields
= 0, timestamp
= 0;
1277 double speed
= 0.0, direction
= 0.0, climb
= 0.0;
1279 DEBUG(GYPSY_COURSE
": GetCourse: Notify");
1281 dbus_g_proxy_end_call(proxy
, call
, &error
,
1282 G_TYPE_INT
, &fields
,
1283 G_TYPE_INT
, ×tamp
,
1284 G_TYPE_DOUBLE
, &speed
,
1285 G_TYPE_DOUBLE
, &direction
,
1286 G_TYPE_DOUBLE
, &climb
,
1290 WARNING(GYPSY_COURSE
": GetCourse: %s", error
->message
);
1291 g_error_free(error
);
1293 DEBUG(GYPSY_COURSE
": GetCourse: OK");
1294 course_changed(NULL
, fields
, timestamp
, speed
, direction
,
1300 get_satellites_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1302 GError
*error
= NULL
;
1303 GPtrArray
*satellites
= NULL
;
1305 DEBUG(GYPSY_SATELLITE
": GetSatellites: Notify");
1307 dbus_g_proxy_end_call(proxy
, call
, &error
,
1308 dbus_g_type_get_collection("GPtrArray",
1309 dbus_g_type_get_struct("GValueArray",
1320 WARNING(GYPSY_SATELLITE
": GetSatellites: %s", error
->message
);
1321 g_error_free(error
);
1323 DEBUG(GYPSY_SATELLITE
": GetSatellites: OK");
1324 satellites_changed(NULL
, satellites
, NULL
);
1328 /******************************************************************************/
1331 device_start_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1333 GError
*error
= NULL
;
1335 DEBUG(GYPSY_DEVICE
": Start: Notify");
1337 dbus_g_proxy_end_call(proxy
, call
, &error
, G_TYPE_INVALID
);
1340 WARNING(GYPSY_DEVICE
": Start: %s", error
->message
);
1341 g_error_free(error
);
1342 gypsy_device_start_failed
= TRUE
;
1344 DEBUG(GYPSY_DEVICE
": Start: OK");
1345 gypsy_device_start_failed
= FALSE
;
1347 DEBUG(GYPSY_DEVICE
": GetConnectionStatus");
1348 dbus_g_proxy_begin_call(device_proxy
, "GetConnectionStatus",
1349 get_connection_status_notify
, NULL
, NULL
,
1352 DEBUG(GYPSY_DEVICE
": GetFixStatus");
1353 dbus_g_proxy_begin_call(device_proxy
, "GetFixStatus",
1354 get_fix_status_notify
, NULL
, NULL
,
1357 DEBUG(GYPSY_TIME
": GetTime");
1358 dbus_g_proxy_begin_call(time_proxy
, "GetTime",
1359 get_time_notify
, NULL
, NULL
,
1362 DEBUG(GYPSY_POSITION
": GetPosition");
1363 dbus_g_proxy_begin_call(position_proxy
, "GetPosition",
1364 get_position_notify
, NULL
, NULL
,
1367 DEBUG(GYPSY_ACCURACY
": GetAccuracy");
1368 dbus_g_proxy_begin_call(accuracy_proxy
, "GetAccuracy",
1369 get_accuracy_notify
, NULL
, NULL
,
1372 DEBUG(GYPSY_COURSE
": GetCourse");
1373 dbus_g_proxy_begin_call(course_proxy
, "GetCourse",
1374 get_course_notify
, NULL
, NULL
,
1377 DEBUG(GYPSY_SATELLITE
": GetSatellites");
1378 dbus_g_proxy_begin_call(satellite_proxy
, "GetSatellites",
1379 get_satellites_notify
, NULL
, NULL
,
1384 /******************************************************************************/
1389 if (!gypsy_device_path
) {
1390 WARNING("No device, not starting");
1394 gypsy_device_start_failed
= FALSE
;
1397 device_proxy
= dbus_g_proxy_new_for_name(connection
,
1398 gypsy_service
, gypsy_device_path
, GYPSY_DEVICE
);
1400 DEBUG(GYPSY_DEVICE
": Start");
1401 dbus_g_proxy_begin_call(device_proxy
, "Start",
1402 device_start_notify
, NULL
, NULL
,
1405 dbus_g_proxy_add_signal(device_proxy
, "ConnectionStatusChanged",
1408 dbus_g_proxy_connect_signal(device_proxy
, "ConnectionStatusChanged",
1409 G_CALLBACK(connection_status_changed
), NULL
, NULL
);
1411 dbus_g_proxy_add_signal(device_proxy
, "FixStatusChanged",
1414 dbus_g_proxy_connect_signal(device_proxy
, "FixStatusChanged",
1415 G_CALLBACK(fix_status_changed
), NULL
, NULL
);
1418 time_proxy
= dbus_g_proxy_new_for_name(connection
,
1419 gypsy_service
, gypsy_device_path
, GYPSY_TIME
);
1421 dbus_g_proxy_add_signal(time_proxy
, "TimeChanged",
1424 dbus_g_proxy_connect_signal(time_proxy
, "TimeChanged",
1425 G_CALLBACK(time_changed
), NULL
, NULL
);
1428 position_proxy
= dbus_g_proxy_new_for_name(connection
,
1429 gypsy_service
, gypsy_device_path
, GYPSY_POSITION
);
1431 dbus_g_proxy_add_signal(position_proxy
, "PositionChanged",
1438 dbus_g_proxy_connect_signal(position_proxy
, "PositionChanged",
1439 G_CALLBACK(position_changed
), NULL
, NULL
);
1442 accuracy_proxy
= dbus_g_proxy_new_for_name(connection
,
1443 gypsy_service
, gypsy_device_path
, GYPSY_ACCURACY
);
1445 dbus_g_proxy_add_signal(accuracy_proxy
, "AccuracyChanged",
1451 dbus_g_proxy_connect_signal(accuracy_proxy
, "AccuracyChanged",
1452 G_CALLBACK(accuracy_changed
), NULL
, NULL
);
1455 course_proxy
= dbus_g_proxy_new_for_name(connection
,
1456 gypsy_service
, gypsy_device_path
, GYPSY_COURSE
);
1458 dbus_g_proxy_add_signal(course_proxy
, "CourseChanged",
1465 dbus_g_proxy_connect_signal(course_proxy
, "CourseChanged",
1466 G_CALLBACK(course_changed
), NULL
, NULL
);
1469 satellite_proxy
= dbus_g_proxy_new_for_name(connection
,
1470 gypsy_service
, gypsy_device_path
, GYPSY_SATELLITE
);
1472 dbus_g_proxy_add_signal(satellite_proxy
, "SatellitesChanged",
1473 dbus_g_type_get_collection("GPtrArray",
1474 dbus_g_type_get_struct("GValueArray",
1482 dbus_g_proxy_connect_signal(satellite_proxy
, "SatellitesChanged",
1483 G_CALLBACK(satellites_changed
), NULL
, NULL
);
1486 /******************************************************************************/
1489 device_stop_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1491 GError
*error
= NULL
;
1493 DEBUG(GYPSY_DEVICE
": Stop: Notify");
1495 dbus_g_proxy_end_call(proxy
, call
, &error
, G_TYPE_INVALID
);
1498 WARNING(GYPSY_DEVICE
": Stop: %s", error
->message
);
1499 g_error_free(error
);
1501 DEBUG(GYPSY_DEVICE
": Stop: OK");
1508 if (!gypsy_device_path
) {
1509 WARNING("No device, not stopping");
1514 if (gypsy_device_start_failed
) {
1515 gypsy_device_start_failed
= FALSE
;
1517 DEBUG(GYPSY_DEVICE
": Stop");
1518 dbus_g_proxy_begin_call(device_proxy
, "Stop",
1519 device_stop_notify
, NULL
, NULL
,
1523 dbus_g_proxy_disconnect_signal(device_proxy
, "ConnectionStatusChanged",
1524 G_CALLBACK(connection_status_changed
), NULL
);
1525 dbus_g_proxy_disconnect_signal(device_proxy
, "FixStatusChanged",
1526 G_CALLBACK(fix_status_changed
), NULL
);
1527 g_object_unref(G_OBJECT(device_proxy
));
1528 device_proxy
= NULL
;
1529 device_connectionstatus
= FALSE
;
1530 device_fixstatus
= 0;
1533 dbus_g_proxy_disconnect_signal(time_proxy
, "TimeChanged",
1534 G_CALLBACK(time_changed
), NULL
);
1535 g_object_unref(G_OBJECT(time_proxy
));
1540 dbus_g_proxy_disconnect_signal(position_proxy
, "PositionChanged",
1541 G_CALLBACK(position_changed
), NULL
);
1542 g_object_unref(G_OBJECT(position_proxy
));
1543 position_proxy
= NULL
;
1544 position_fields
= 0;
1545 position_timestamp
= 0;
1546 position_latitude
= 0.0;
1547 position_longitude
= 0.0;
1548 position_altitude
= 0.0;
1551 dbus_g_proxy_disconnect_signal(accuracy_proxy
, "AccuracyChanged",
1552 G_CALLBACK(accuracy_changed
), NULL
);
1553 g_object_unref(G_OBJECT(accuracy_proxy
));
1554 accuracy_proxy
= NULL
;
1555 accuracy_fields
= 0;
1556 accuracy_pdop
= 0.0;
1557 accuracy_hdop
= 0.0;
1558 accuracy_vdop
= 0.0;
1561 dbus_g_proxy_disconnect_signal(course_proxy
, "CourseChanged",
1562 G_CALLBACK(course_changed
), NULL
);
1563 g_object_unref(G_OBJECT(course_proxy
));
1564 course_proxy
= NULL
;
1566 course_timestamp
= 0;
1568 course_direction
= 0.0;
1572 dbus_g_proxy_disconnect_signal(satellite_proxy
, "SatellitesChanged",
1573 G_CALLBACK(satellites_changed
), NULL
);
1574 g_object_unref(G_OBJECT(satellite_proxy
));
1575 satellite_proxy
= NULL
;
1576 satellite_satellitec
= 0;
1579 /******************************************************************************/
1582 server_create_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1584 GError
*error
= NULL
;
1585 const char *path
= NULL
;
1587 DEBUG(GYPSY_SERVER
": Create: Notify");
1589 dbus_g_proxy_end_call(proxy
, call
, &error
,
1590 DBUS_TYPE_G_OBJECT_PATH
, &path
,
1594 WARNING(GYPSY_SERVER
": Create: %s", error
->message
);
1595 g_error_free(error
);
1596 gypsy_device_create_failed
= TRUE
;
1597 gypsy_device_path
= NULL
;
1599 DEBUG(GYPSY_SERVER
": Create: OK: %s", path
);
1600 gypsy_device_create_failed
= FALSE
;
1601 gypsy_device_path
= g_strdup(path
);
1603 if (client_list
|| nowait
) {
1612 gypsy_device_create_failed
= FALSE
;
1614 DEBUG(GYPSY_SERVER
": Create");
1615 dbus_g_proxy_begin_call(server_proxy
, "Create",
1616 server_create_notify
, NULL
, NULL
,
1617 G_TYPE_STRING
, gypsy_device
,
1621 /******************************************************************************/
1632 INFO("org.freedesktop.DBus: NameOwnerChanged(name=%s, prev=%s, new=%s)",
1635 if (name
&& !strcmp(name
, gypsy_service
)) {
1636 if (prev
&& strlen(prev
) > 0) {
1637 g_free(gypsy_device_path
);
1639 if (new && strlen(new) > 0) {
1642 gypsy_device_path
= NULL
;
1646 /******************************************************************************/
1649 timeout_handler(gpointer data
)
1651 if (!client_list
&& !nowait
) {
1652 DEBUG("Timeout: no client: removing timeout handler");
1653 timeout_handler_registered
= FALSE
;
1656 if (gypsy_device_create_failed
) {
1657 WARNING("Timeout: no gypsy device created");
1659 } else if (!gypsy_device_path
) {
1660 WARNING("Timeout: no gypsy device available");
1661 } else if (gypsy_device_start_failed
) {
1662 WARNING("Timeout: gypsy device not started");
1663 DEBUG(GYPSY_DEVICE
": Start");
1664 dbus_g_proxy_begin_call(device_proxy
, "Start",
1665 device_start_notify
, NULL
, NULL
,
1667 } else if (!device_connectionstatus
) {
1668 WARNING("Timeout: device started but not connected");
1672 DEBUG("Timeout: sending data to clients");
1674 g_get_current_time(&tv
);
1676 send_info_to_clients(&tv
);
1677 send_sats_to_clients(&tv
);
1678 send_nmea_to_clients(&tv
);
1684 /******************************************************************************/
1687 marshal_VOID__STRING_STRING_STRING(
1689 GValue
*return_value G_GNUC_UNUSED
,
1690 guint n_param_values
,
1691 const GValue
*param_values
,
1692 gpointer invocation_hint G_GNUC_UNUSED
,
1693 gpointer marshal_data
1696 typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING
)(
1703 GMarshalFunc_VOID__STRING_STRING_STRING callback
;
1704 GCClosure
*cc
= (GCClosure
*) closure
;
1705 gpointer data1
, data2
;
1707 g_return_if_fail (n_param_values
== 4);
1709 if (G_CCLOSURE_SWAP_DATA(closure
)) {
1710 data1
= closure
->data
;
1711 data2
= g_value_peek_pointer(param_values
+ 0);
1713 data1
= g_value_peek_pointer(param_values
+ 0);
1714 data2
= closure
->data
;
1717 callback
= (GMarshalFunc_VOID__STRING_STRING_STRING
) (
1718 marshal_data
? marshal_data
: cc
->callback
);
1721 (const gchar
*) g_value_get_string(param_values
+ 1),
1722 (const gchar
*) g_value_get_string(param_values
+ 2),
1723 (const gchar
*) g_value_get_string(param_values
+ 3),
1728 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE(
1730 GValue
*return_value G_GNUC_UNUSED
,
1731 guint n_param_values
,
1732 const GValue
*param_values
,
1733 gpointer invocation_hint G_GNUC_UNUSED
,
1734 gpointer marshal_data
1737 typedef void (*GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
)(
1746 GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE callback
;
1747 GCClosure
*cc
= (GCClosure
*) closure
;
1748 gpointer data1
, data2
;
1750 g_return_if_fail(n_param_values
== 6);
1752 if (G_CCLOSURE_SWAP_DATA(closure
)) {
1753 data1
= closure
->data
;
1754 data2
= g_value_peek_pointer(param_values
+ 0);
1756 data1
= g_value_peek_pointer(param_values
+ 0);
1757 data2
= closure
->data
;
1760 callback
= (GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
) (
1761 marshal_data
? marshal_data
: cc
->callback
);
1764 g_value_get_int(param_values
+ 1),
1765 g_value_get_int(param_values
+ 2),
1766 g_value_get_double(param_values
+ 3),
1767 g_value_get_double(param_values
+ 4),
1768 g_value_get_double(param_values
+ 5),
1773 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE(
1775 GValue
*return_value G_GNUC_UNUSED
,
1776 guint n_param_values
,
1777 const GValue
*param_values
,
1778 gpointer invocation_hint G_GNUC_UNUSED
,
1779 gpointer marshal_data
1782 typedef void (*GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE
)(
1790 GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE callback
;
1791 GCClosure
*cc
= (GCClosure
*) closure
;
1792 gpointer data1
, data2
;
1794 g_return_if_fail(n_param_values
== 5);
1796 if (G_CCLOSURE_SWAP_DATA(closure
)) {
1797 data1
= closure
->data
;
1798 data2
= g_value_peek_pointer(param_values
+ 0);
1800 data1
= g_value_peek_pointer(param_values
+ 0);
1801 data2
= closure
->data
;
1804 callback
= (GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE
) (
1805 marshal_data
? marshal_data
: cc
->callback
);
1808 g_value_get_int(param_values
+ 1),
1809 g_value_get_double(param_values
+ 2),
1810 g_value_get_double(param_values
+ 3),
1811 g_value_get_double(param_values
+ 4),
1815 /******************************************************************************/
1818 read_from_client(GIOChannel
*source
, GIOCondition condition
, gpointer data
)
1820 struct client
*client
;
1822 gsize len
= sizeof(buf
);
1829 if (condition
!= G_IO_IN
) {
1830 shutdown_client(client
);
1833 if (!client
->channel
) {
1834 MESSAGE("Removing client");
1836 client_list
= g_list_remove(client_list
, client
);
1838 g_io_channel_unref(source
);
1840 if (!client_list
&& !nowait
) {
1847 status
= g_io_channel_read_chars(source
, buf
, len
- 2, &len
, NULL
);
1849 if ((status
!= G_IO_STATUS_NORMAL
) || (len
< 1)) {
1850 shutdown_client(client
);
1854 if (buf
[len
- 1] != '\n') {
1861 reply
= g_string_sized_new(128);
1862 g_string_assign(reply
, "GPSD");
1867 switch (toupper(*p
++)) {
1869 if (!POSITION_ALTITUDE_IS_VALID
) {
1870 g_string_append(reply
, ",A=?");
1872 g_string_append_printf(reply
, ",A=%.3f",
1877 g_string_append(reply
, ",B=?");
1880 g_string_append(reply
, ",C=1.00"); /* FIXME */
1883 if (time_seconds
<= 0) {
1884 g_string_append(reply
, ",D=?");
1889 seconds
= time_seconds
;
1890 tm
= gmtime(&seconds
);
1892 g_string_append_printf(reply
,
1893 ",D=%04d-%02d-%02dT%02d:%02d:%02d.00Z",
1894 tm
->tm_year
+ 1900, tm
->tm_mon
+ 1,
1895 tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
,
1900 g_string_append(reply
, ",E=");
1902 if (!ACCURACY_PDOP_IS_VALID
) {
1903 g_string_append(reply
, "?");
1905 g_string_append_printf(reply
, "%.2f",
1908 if (!ACCURACY_HDOP_IS_VALID
) {
1909 g_string_append(reply
, " ?");
1911 g_string_append_printf(reply
, " %.2f",
1914 if (!ACCURACY_VDOP_IS_VALID
) {
1915 g_string_append(reply
, " ?");
1917 g_string_append_printf(reply
, " %.2f",
1923 while (isprint(*p
) && !isspace(*p
)) {
1927 g_string_append(reply
, ",F=gypsy");
1931 p
+= strcspn(p
, ",\r\n");
1933 g_string_append(reply
, ",G=GPS");
1936 g_string_append(reply
, ",I=gypsy");
1942 if (*p
== '1' || *p
== '+') {
1944 g_string_append(reply
, ",J=1");
1946 if (*p
== '0' || *p
== '-') {
1949 g_string_append(reply
, ",J=0");
1953 g_string_append(reply
, ",K=1 gypsy");
1956 g_string_append(reply
, ",L=3 " VERSION
1957 " abcdefgijklmnopqrstuvwxyz");
1960 g_string_append_printf(reply
, ",M=%d",
1964 g_string_append(reply
, ",N=0");
1970 if (!POSITION_LATITUDE_IS_VALID
1971 || !POSITION_LONGITUDE_IS_VALID
) {
1972 g_string_append(reply
, ",P=?");
1974 g_string_append_printf(reply
, ",P=%.6f %.6f",
1975 position_latitude
, position_longitude
);
1979 if (!ACCURACY_PDOP_IS_VALID
1980 && !ACCURACY_HDOP_IS_VALID
1981 && !ACCURACY_VDOP_IS_VALID
) {
1982 g_string_append(reply
, ",Q=?");
1986 for (i
= 0, used
= 0; i
< satellite_satellitec
; i
++) {
1987 if (satellite_satellitev
[i
].used
) {
1992 g_string_append_printf(reply
,
1993 ",Q=%d %.2f %.2f %.2f %.2f %.2f", used
,
1994 ACCURACY_PDOP_IS_VALID
? accuracy_pdop
: 0.0,
1995 ACCURACY_HDOP_IS_VALID
? accuracy_hdop
: 0.0,
1996 ACCURACY_VDOP_IS_VALID
? accuracy_vdop
: 0.0,
2004 if (*p
== '2' || *p
== '1' || *p
== '+') {
2007 } else if (*p
== '0' || *p
== '-') {
2008 client
->raw
= FALSE
;
2011 client
->raw
= !client
->raw
;
2013 g_string_append_printf(reply
, ",R=%1d", client
->raw
);
2016 g_string_append_printf(reply
, ",S=%d",
2017 MAX(get_fixstatus() - 1, 0));
2020 if (!COURSE_DIRECTION_IS_VALID
) {
2021 g_string_append(reply
, ",T=?");
2023 g_string_append_printf(reply
, ",T=%.4f",
2028 if (!COURSE_CLIMB_IS_VALID
) {
2029 g_string_append(reply
, ",U=?");
2031 g_string_append_printf(reply
, ",U=%.3f",
2036 if (!COURSE_SPEED_IS_VALID
) {
2037 g_string_append(reply
, ",V=?");
2039 g_string_append_printf(reply
, ",V=%.3f",
2040 course_speed
* KNOTS_TO_MPS
);
2047 if (*p
== '1' || *p
== '+') {
2048 client
->watcher
= TRUE
;
2050 } else if (*p
== '0' || *p
== '-') {
2051 client
->watcher
= FALSE
;
2054 client
->watcher
= !client
->watcher
;
2056 g_string_append_printf(reply
, ",W=%1d", client
->watcher
);
2059 if (time_seconds
<= 0) {
2060 g_string_append(reply
, ",X=?");
2062 g_string_append_printf(reply
, ",X=%d.000000",
2070 g_string_append(reply
, ",Z=?"); /* FIXME */
2073 g_string_append(reply
, ",$=?"); /* FIXME */
2084 g_string_append(reply
, "\r\n");
2085 send_to_client(client
, reply
->str
, reply
->len
);
2086 g_string_free(reply
, TRUE
);
2091 accept_new_client(GIOChannel
*source
, GIOCondition condition
, gpointer data
)
2093 struct sockaddr_in addr
;
2094 socklen_t len
= sizeof(addr
);
2095 struct client
*client
;
2098 MESSAGE("New client request");
2100 fd
= accept(g_io_channel_unix_get_fd(source
),
2101 (struct sockaddr
*) &addr
, &len
);
2104 ERROR("Cannot accept new connection: %s", strerror(errno
));
2107 client
= g_new0(struct client
, 1);
2110 ERROR("Cannot allocate memory");
2113 if (!timeout_handler_registered
) {
2114 timeout_handler_registered
= TRUE
;
2115 g_timeout_add(2000, timeout_handler
, NULL
);
2118 if (!client_list
&& !nowait
) {
2122 client_list
= g_list_prepend(client_list
, client
);
2124 client
->channel
= g_io_channel_unix_new(fd
);
2126 g_io_channel_set_flags(client
->channel
, G_IO_FLAG_NONBLOCK
, NULL
);
2127 g_io_channel_set_encoding(client
->channel
, NULL
, NULL
);
2128 g_io_channel_set_buffered(client
->channel
, FALSE
);
2130 g_io_add_watch(client
->channel
,
2131 G_IO_IN
| G_IO_PRI
| G_IO_ERR
| G_IO_HUP
| G_IO_NVAL
,
2132 read_from_client
, client
);
2138 init_tcp_service(const char *tcp_service
)
2140 struct servent
*pse
;
2141 struct sockaddr_in addr
;
2142 GIOChannel
*channel
;
2145 memset(&addr
, 0, sizeof(addr
));
2147 addr
.sin_family
= AF_INET
;
2148 addr
.sin_addr
.s_addr
= INADDR_ANY
;
2151 tcp_service
= "2947";
2154 pse
= getservbyname(tcp_service
, "tcp");
2157 addr
.sin_port
= pse
->s_port
;
2159 addr
.sin_port
= htons(atoi(tcp_service
));
2162 if (!addr
.sin_port
) {
2163 ERROR("Cannot get service entry: %s", tcp_service
);
2166 fd
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
2169 ERROR("Cannot create socket: %s", strerror(errno
));
2172 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) & one
, sizeof(one
));
2174 if (bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
2175 ERROR("Cannot bind to port: %s: %s",
2176 tcp_service
, strerror(errno
));
2179 if (listen(fd
, 4) < 0) {
2180 ERROR("Cannot listen on port: %s: %s",
2181 tcp_service
, strerror(errno
));
2184 channel
= g_io_channel_unix_new(fd
);
2186 g_io_channel_set_encoding(channel
, NULL
, NULL
);
2187 g_io_channel_set_buffered(channel
, FALSE
);
2189 g_io_add_watch(channel
, G_IO_IN
| G_IO_PRI
| G_IO_HUP
| G_IO_ERR
,
2190 accept_new_client
, NULL
);
2193 /******************************************************************************/
2196 printerr_handler(const char *message
)
2199 syslog(LOG_USER
| LOG_INFO
, "%s", message
);
2201 fputs(message
, stderr
);
2208 GLogLevelFlags level
,
2209 const char *message
,
2213 const char *level_string
;
2215 switch (level
& G_LOG_LEVEL_MASK
) {
2216 case G_LOG_LEVEL_ERROR
:
2217 level_string
= "ERROR: ";
2219 case G_LOG_LEVEL_CRITICAL
:
2220 level_string
= "CRITICAL: ";
2222 case G_LOG_LEVEL_WARNING
:
2223 level_string
= "WARNING: ";
2225 case G_LOG_LEVEL_MESSAGE
:
2226 level_string
= "MESSAGE: ";
2228 case G_LOG_LEVEL_INFO
:
2229 level_string
= "INFO: ";
2231 case G_LOG_LEVEL_DEBUG
:
2232 level_string
= "DEBUG: ";
2241 syslog(LOG_USER
| LOG_INFO
, "%s: %s%s", domain
,
2242 level_string
, message
);
2244 syslog(LOG_USER
| LOG_INFO
, "%s%s",
2245 level_string
, message
);
2248 struct timeval tv
= { 0, 0 };
2253 gettimeofday(&tv
, NULL
);
2254 tm
= localtime(&tv
.tv_sec
);
2255 len
= strftime(buf
, sizeof(buf
), "%T", tm
);
2262 fprintf(stderr
, "%s.%06li %s: %s%s\n", buf
,
2263 (long) tv
.tv_usec
, domain
, level_string
,
2266 fprintf(stderr
, "%s.%06li %s%s\n", buf
,
2267 (long) tv
.tv_usec
, level_string
, message
);
2272 /******************************************************************************/
2277 printf("usage: "PACKAGE_NAME
" [-n] [-N] [-D n] [-P pidfile] [-S port] [-h]\n\
2279 -n = don't wait for client connects to poll GPS\n\
2280 -N = don't go into background\n\
2281 -P pidfile = set file to record process ID\n\
2282 -D integer (default 0) = set debug level\n\
2283 -S integer (default 2947) = set port for daemon\n\
2284 -h = help message\n\
2285 -V = emit version and exit.\n");
2288 /******************************************************************************/
2291 main(int argc
, char **argv
)
2293 DBusGProxy
*proxy_dbus
= NULL
;
2294 GMainLoop
*loop
= NULL
;
2295 char *tcp_service
= NULL
;
2296 char *pid_file
= NULL
;
2297 gboolean foreground
= FALSE
;
2298 GError
*error
= NULL
;
2300 g_set_prgname(PACKAGE_NAME
);
2301 g_set_printerr_handler(printerr_handler
);
2302 g_log_set_default_handler(log_handler
, NULL
);
2308 option
= getopt(argc
, argv
, "F:D:S:bhNnP:VR:");
2318 WARNING("Not implemented: -%c", option
);
2321 switch (atoi(optarg
)) {
2323 log_level
= G_LOG_LEVEL_ERROR
2324 | G_LOG_LEVEL_CRITICAL
2325 | G_LOG_LEVEL_WARNING
;
2328 log_level
= G_LOG_LEVEL_ERROR
2329 | G_LOG_LEVEL_CRITICAL
2330 | G_LOG_LEVEL_WARNING
2331 | G_LOG_LEVEL_MESSAGE
;
2334 log_level
= G_LOG_LEVEL_ERROR
2335 | G_LOG_LEVEL_CRITICAL
2336 | G_LOG_LEVEL_WARNING
2337 | G_LOG_LEVEL_MESSAGE
2341 log_level
= G_LOG_LEVEL_ERROR
2342 | G_LOG_LEVEL_CRITICAL
2343 | G_LOG_LEVEL_WARNING
2344 | G_LOG_LEVEL_MESSAGE
2346 | G_LOG_LEVEL_DEBUG
;
2354 tcp_service
= optarg
;
2363 printf(PACKAGE_NAME
" "VERSION
"\n");
2382 ERROR("Cannot fork: %s", strerror(errno
));
2383 } else if (pid
> 0) {
2387 openlog(PACKAGE_NAME
, LOG_PID
, LOG_USER
);
2393 fd
= open("/dev/null", O_RDWR
, 0);
2396 ERROR("Cannot open: /dev/null: %s", strerror(errno
));
2399 dup2(fd
, STDIN_FILENO
);
2400 dup2(fd
, STDOUT_FILENO
);
2401 dup2(fd
, STDERR_FILENO
);
2409 fp
= fopen(pid_file
, "w");
2412 ERROR("Cannot fopen: %s: %s", pid_file
, strerror(errno
));
2415 fprintf(fp
, "%u\n", (unsigned) getpid());
2421 loop
= g_main_loop_new(NULL
, FALSE
);
2423 connection
= dbus_g_bus_get(DBUS_BUS_SYSTEM
, &error
);
2426 ERROR("Failed to open connection to system bus: %s\n",
2430 dbus_g_object_register_marshaller(
2431 marshal_VOID__STRING_STRING_STRING
,
2437 dbus_g_object_register_marshaller(
2438 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE
,
2445 dbus_g_object_register_marshaller(
2446 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
,
2455 proxy_dbus
= dbus_g_proxy_new_for_name(connection
,
2456 "org.freedesktop.DBus", "/org/freedesktop/DBus",
2457 "org.freedesktop.DBus");
2459 server_proxy
= dbus_g_proxy_new_for_name(connection
,
2460 gypsy_service
, gypsy_server_path
, GYPSY_SERVER
);
2462 dbus_g_proxy_add_signal(proxy_dbus
, "NameOwnerChanged",
2467 dbus_g_proxy_connect_signal(proxy_dbus
, "NameOwnerChanged",
2468 G_CALLBACK(name_owner_changed
), NULL
, NULL
);
2472 nmea_gga
= g_string_sized_new(128);
2473 nmea_gsa
= g_string_sized_new(128);
2474 nmea_gsv
[0] = g_string_sized_new(128);
2475 nmea_gsv
[1] = g_string_sized_new(128);
2476 nmea_gsv
[2] = g_string_sized_new(128);
2477 nmea_rmc
= g_string_sized_new(128);
2478 nmea_gll
= g_string_sized_new(128);
2479 nmea_vtg
= g_string_sized_new(128);
2481 init_tcp_service(tcp_service
);
2484 timeout_handler_registered
= TRUE
;
2485 g_timeout_add(2000, timeout_handler
, NULL
);
2488 g_main_loop_run(loop
);