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/socket.h>
31 #include <sys/types.h>
34 #include <dbus/dbus-glib.h>
35 #include <glib-object.h>
38 #define KNOTS_TO_KPH (1.852)
39 #define KNOTS_TO_MPS (0.51444444)
41 /******************************************************************************/
45 g_log(NULL, G_LOG_LEVEL_ERROR, __VA_ARGS__); \
49 #define CRITICAL(...) \
51 if (G_UNLIKELY(log_level & G_LOG_LEVEL_CRITICAL)) { \
52 g_log(NULL, G_LOG_LEVEL_CRITICAL, __VA_ARGS__); \
56 #define WARNING(...) \
58 if (G_UNLIKELY(log_level & G_LOG_LEVEL_WARNING)) { \
59 g_log(NULL, G_LOG_LEVEL_WARNING, __VA_ARGS__); \
63 #define MESSAGE(...) \
65 if (G_UNLIKELY(log_level & G_LOG_LEVEL_MESSAGE)) { \
66 g_log(NULL, G_LOG_LEVEL_MESSAGE, __VA_ARGS__); \
72 if (G_UNLIKELY(log_level & G_LOG_LEVEL_INFO)) { \
73 g_log(NULL, G_LOG_LEVEL_INFO, __VA_ARGS__); \
79 if (G_UNLIKELY(log_level & G_LOG_LEVEL_DEBUG)) { \
80 g_log(NULL, G_LOG_LEVEL_DEBUG, __VA_ARGS__); \
84 /******************************************************************************/
86 #define POSITION_LATITUDE_IS_VALID (position_fields & (1 << 0))
87 #define POSITION_LONGITUDE_IS_VALID (position_fields & (1 << 1))
88 #define POSITION_ALTITUDE_IS_VALID (position_fields & (1 << 2))
90 #define ACCURACY_PDOP_IS_VALID (accuracy_fields & (1 << 0))
91 #define ACCURACY_HDOP_IS_VALID (accuracy_fields & (1 << 1))
92 #define ACCURACY_VDOP_IS_VALID (accuracy_fields & (1 << 2))
94 #define COURSE_SPEED_IS_VALID (course_fields & (1 << 0))
95 #define COURSE_DIRECTION_IS_VALID (course_fields & (1 << 1))
96 #define COURSE_CLIMB_IS_VALID (course_fields & (1 << 2))
98 /******************************************************************************/
114 /******************************************************************************/
116 static int log_level
= G_LOG_LEVEL_ERROR
117 | G_LOG_LEVEL_CRITICAL
118 | G_LOG_LEVEL_WARNING
;
120 static gboolean background
= FALSE
;
121 static gboolean nowait
= FALSE
;
123 /******************************************************************************/
125 static gboolean info_queued
= FALSE
;
126 static gboolean sats_queued
= FALSE
;
127 static gboolean nmea_queued
= FALSE
;
129 /******************************************************************************/
131 static gboolean timeout_handler_registered
= FALSE
;
133 /******************************************************************************/
135 static GList
*client_list
= NULL
;
137 /******************************************************************************/
139 static DBusGConnection
*connection
= NULL
;
141 /******************************************************************************/
143 static const char *gypsy_device
= "";
144 static const char *gypsy_service
= "org.freedesktop.Gypsy";
145 static const char *gypsy_server_path
= "/org/freedesktop/Gypsy";
146 static char *gypsy_device_path
= NULL
;
148 static gboolean gypsy_device_create_failed
= FALSE
;
149 static gboolean gypsy_device_start_failed
= FALSE
;
151 /******************************************************************************/
153 #define GYPSY_SERVER "org.freedesktop.Gypsy.Server"
154 static DBusGProxy
*server_proxy
= NULL
;
156 #define GYPSY_DEVICE "org.freedesktop.Gypsy.Device"
157 static DBusGProxy
*device_proxy
= NULL
;
158 static gboolean device_connectionstatus
= 0;
159 static int device_fixstatus
= 0; /* 0=INVALID, 1=NONE, 2=2D, 3=3D */
161 #define GYPSY_TIME "org.freedesktop.Gypsy.Time"
162 static DBusGProxy
*time_proxy
= NULL
;
163 static int time_seconds
= 0;
165 #define GYPSY_POSITION "org.freedesktop.Gypsy.Position"
166 static DBusGProxy
*position_proxy
= NULL
;
167 static int position_fields
= 0;
168 static int position_timestamp
= 0;
169 static double position_latitude
= 0.0;
170 static double position_longitude
= 0.0;
171 static double position_altitude
= 0.0;
173 #define GYPSY_ACCURACY "org.freedesktop.Gypsy.Accuracy"
174 static DBusGProxy
*accuracy_proxy
= NULL
;
175 static int accuracy_fields
= 0;
176 static double accuracy_pdop
= 0.0;
177 static double accuracy_hdop
= 0.0;
178 static double accuracy_vdop
= 0.0;
180 #define GYPSY_COURSE "org.freedesktop.Gypsy.Course"
181 static DBusGProxy
*course_proxy
= NULL
;
182 static int course_fields
= 0;
183 static int course_timestamp
= 0;
184 static double course_speed
= 0.0;
185 static double course_direction
= 0.0;
186 static double course_climb
= 0.0;
188 #define GYPSY_SATELLITE "org.freedesktop.Gypsy.Satellite"
189 static DBusGProxy
*satellite_proxy
= NULL
;
190 #define SATELLITEC_MAX 12
191 static struct satellite satellite_satellitev
[SATELLITEC_MAX
];
192 static unsigned satellite_satellitec
= 0;
194 /******************************************************************************/
196 static GString
*nmea_gga
;
197 static GString
*nmea_gsa
;
198 static GString
*nmea_gsv
[3];
199 static GString
*nmea_rmc
;
200 static GString
*nmea_gll
;
201 static GString
*nmea_vtg
;
203 /******************************************************************************/
208 if (POSITION_LATITUDE_IS_VALID
&& POSITION_LONGITUDE_IS_VALID
) {
209 if (POSITION_ALTITUDE_IS_VALID
) {
210 return MIN(device_fixstatus
, 3);
212 return MIN(device_fixstatus
, 2);
215 return MIN(device_fixstatus
, 1);
220 check_period(const GTimeVal
*tv1
, const GTimeVal
*tv2
, glong sec
)
222 glong tv1_sec
= tv1
->tv_sec
+ sec
;
223 glong tv1_usec
= tv1
->tv_usec
;
224 glong tv2_sec
= tv2
->tv_sec
;
225 glong tv2_usec
= tv2
->tv_usec
;
227 if (tv1_sec
== tv2_sec
) {
228 return (tv1_usec
> tv2_usec
);
230 return (tv1_sec
> tv2_sec
);
234 /******************************************************************************/
237 shutdown_client(struct client
*client
)
239 if (client
->channel
) {
240 MESSAGE("Shutdown client");
242 g_io_channel_shutdown(client
->channel
, FALSE
, NULL
);
245 client
->channel
= NULL
;
246 client
->watcher
= FALSE
;
251 send_to_client(struct client
*client
, const char *string
, gsize len
)
256 if (!client
->channel
) {
260 status
= g_io_channel_write_chars(client
->channel
, string
,
261 len
, &bytes_written
, NULL
);
263 if ((bytes_written
!= len
) || (status
!= G_IO_STATUS_NORMAL
)) {
264 shutdown_client(client
);
268 /******************************************************************************/
271 add_nmea_checksum(GString
*nmea
)
283 checksum
^= (int) *p
;
287 g_string_append_printf(nmea
, "*%02x", checksum
);
291 add_nmea_time(GString
*nmea
)
293 if (time_seconds
<= 0) {
294 g_string_append_c(nmea
, ',');
299 seconds
= time_seconds
;
300 tm
= gmtime(&seconds
);
302 g_string_append_printf(nmea
, ",%02d%02d%02d.00",
303 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
308 add_nmea_latitude(GString
*nmea
)
310 if (!POSITION_LATITUDE_IS_VALID
) {
311 g_string_append_c(nmea
, ',');
312 g_string_append_c(nmea
, ',');
316 a
= fabs(position_latitude
);
319 g_string_append_printf(nmea
, ",%010.5f,%c",
320 (d
* 100.0) + ((a
- d
) * 60.0),
321 (position_latitude
> 0) ? 'N' : 'S');
326 add_nmea_longitude(GString
*nmea
)
328 if (!POSITION_LONGITUDE_IS_VALID
) {
329 g_string_append_c(nmea
, ',');
330 g_string_append_c(nmea
, ',');
334 a
= fabs(position_longitude
);
337 g_string_append_printf(nmea
, ",%011.5f,%c",
338 (d
* 100.0) + ((a
- d
) * 60.0),
339 (position_longitude
> 0) ? 'E' : 'W');
343 /******************************************************************************/
346 update_nmea_gga(void)
350 g_string_assign(nmea_gga
, "$GPGGA");
352 add_nmea_time(nmea_gga
);
354 add_nmea_latitude(nmea_gga
);
356 add_nmea_longitude(nmea_gga
);
358 g_string_append_printf(nmea_gga
, ",%1d", MAX(get_fixstatus() - 1, 0));
360 for (i
= 0, used
= 0; i
< satellite_satellitec
; i
++) {
361 if (satellite_satellitev
[i
].used
) {
366 g_string_append_printf(nmea_gga
, ",%02d", used
);
368 if (!ACCURACY_HDOP_IS_VALID
) {
369 g_string_append_c(nmea_gga
, ',');
371 g_string_append_printf(nmea_gga
, ",%04.2f", accuracy_hdop
);
374 if (!POSITION_ALTITUDE_IS_VALID
) {
375 g_string_append_c(nmea_gga
, ',');
376 g_string_append_c(nmea_gga
, ',');
378 g_string_append_printf(nmea_gga
, ",%03.1f,M",
382 g_string_append_c(nmea_gga
, ','); /* FIXME */
383 g_string_append_c(nmea_gga
, ',');
384 g_string_append_c(nmea_gga
, ',');
385 g_string_append_c(nmea_gga
, ',');
387 add_nmea_checksum(nmea_gga
);
391 update_nmea_gsa(void)
395 g_string_assign(nmea_gsa
, "$GPGSA");
397 g_string_append_c(nmea_gsa
, ',');
398 g_string_append_c(nmea_gsa
, 'A');
400 g_string_append_printf(nmea_gsa
, ",%1d", MAX(get_fixstatus() - 1, 0));
402 for (i
= 0; i
< 12; i
++) {
403 if (i
< satellite_satellitec
) {
404 g_string_append_printf(nmea_gsa
, ",%02d",
405 satellite_satellitev
[i
].prn
);
407 g_string_append_c(nmea_gsa
, ',');
411 if (!ACCURACY_PDOP_IS_VALID
) {
412 g_string_append_c(nmea_gsa
, ',');
414 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_pdop
);
417 if (!ACCURACY_HDOP_IS_VALID
) {
418 g_string_append_c(nmea_gsa
, ',');
420 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_hdop
);
423 if (!ACCURACY_VDOP_IS_VALID
) {
424 g_string_append_c(nmea_gsa
, ',');
426 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_vdop
);
429 add_nmea_checksum(nmea_gsa
);
433 update_nmea_gsv(void)
437 unsigned sentence_count
;
439 g_string_truncate(nmea_gsv
[0], 0);
440 g_string_truncate(nmea_gsv
[1], 0);
441 g_string_truncate(nmea_gsv
[2], 0);
443 if (satellite_satellitec
== 0) {
444 g_string_assign(nmea_gsv
[0], "$GPGSV,1,1,00*79");
448 sat_count
= MIN(satellite_satellitec
, 12);
449 sentence_count
= ((sat_count
- 1) / 4) + 1;
451 for (i
= 0; i
< sat_count
; i
++) {
452 int index_div
, index_mod
;
457 if (index_mod
== 0) {
458 g_string_append_printf(nmea_gsv
[index_div
],
459 "$GPGSV,%1d,%1d,%02d",
465 g_string_append_printf(nmea_gsv
[index_div
],
466 ",%02u,%02u,%03u,%02u",
467 satellite_satellitev
[i
].prn
,
468 satellite_satellitev
[i
].elevation
,
469 satellite_satellitev
[i
].azimuth
,
470 satellite_satellitev
[i
].snr
);
473 for (i
= 0; i
< 3; i
++) {
474 if (nmea_gsv
[i
]->len
> 0) {
475 add_nmea_checksum(nmea_gsv
[i
]);
481 update_nmea_rmc(void)
483 g_string_assign(nmea_rmc
, "$GPRMC");
485 add_nmea_time(nmea_rmc
);
487 if (get_fixstatus() > 1) {
488 g_string_append_c(nmea_rmc
, ',');
489 g_string_append_c(nmea_rmc
, 'A');
491 g_string_append_c(nmea_rmc
, ',');
492 g_string_append_c(nmea_rmc
, 'V');
495 add_nmea_latitude(nmea_rmc
);
497 add_nmea_longitude(nmea_rmc
);
499 if (!COURSE_SPEED_IS_VALID
) {
500 g_string_append_c(nmea_rmc
, ',');
502 g_string_append_printf(nmea_rmc
, ",%07.3f",
506 if (!COURSE_DIRECTION_IS_VALID
) {
507 g_string_append_c(nmea_rmc
, ',');
509 g_string_append_printf(nmea_rmc
, ",%06.2f",
513 if (time_seconds
<= 0) {
514 g_string_append_c(nmea_rmc
, ',');
519 seconds
= time_seconds
;
520 tm
= gmtime(&seconds
);
522 g_string_append_printf(nmea_rmc
, ",%02d%02d%02d",
523 tm
->tm_mday
, tm
->tm_mon
+ 1, tm
->tm_year
% 100);
526 g_string_append_c(nmea_rmc
, ',');
527 g_string_append_c(nmea_rmc
, ',');
529 add_nmea_checksum(nmea_rmc
);
533 update_nmea_gll(void)
535 g_string_assign(nmea_gll
, "$GPGLL");
537 add_nmea_latitude(nmea_gll
);
539 add_nmea_longitude(nmea_gll
);
541 add_nmea_time(nmea_gll
);
543 if (get_fixstatus() > 1) {
544 g_string_append_c(nmea_gll
, ',');
545 g_string_append_c(nmea_gll
, 'A');
547 g_string_append_c(nmea_gll
, ',');
548 g_string_append_c(nmea_gll
, 'V');
551 add_nmea_checksum(nmea_gll
);
555 update_nmea_vtg(void)
557 g_string_assign(nmea_vtg
, "$GPVTG");
559 if (!COURSE_DIRECTION_IS_VALID
) {
560 g_string_append_c(nmea_vtg
, ',');
561 g_string_append_c(nmea_vtg
, ',');
563 g_string_append_printf(nmea_vtg
, ",%04.2f,T", course_direction
);
566 g_string_append_c(nmea_vtg
, ','); /* FIXME */
567 g_string_append_c(nmea_vtg
, ',');
569 if (!COURSE_SPEED_IS_VALID
) {
570 g_string_append_c(nmea_vtg
, ',');
571 g_string_append_c(nmea_vtg
, ',');
572 g_string_append_c(nmea_vtg
, ',');
573 g_string_append_c(nmea_vtg
, ',');
575 g_string_append_printf(nmea_vtg
, ",%05.3f,N,%05.3f,K",
576 course_speed
, course_speed
* KNOTS_TO_KPH
);
579 add_nmea_checksum(nmea_vtg
);
582 /******************************************************************************/
585 send_nmea_to_clients(gpointer data
)
590 for (string
= NULL
, l
= client_list
; l
; l
= l
->next
) {
591 struct client
*client
= l
->data
;
595 static GTimeVal timestamp
= { 0, 0 };
597 if (data
&& check_period(×tamp
, data
, 1)) {
601 g_get_current_time(×tamp
);
603 string
= g_string_sized_new(1024);
605 if (!nmea_gga
->len
) {
608 if (!nmea_gsa
->len
) {
611 if (!nmea_gsv
[0]->len
) {
614 if (!nmea_rmc
->len
) {
617 if (!nmea_gll
->len
) {
620 if (!nmea_vtg
->len
) {
625 INFO("Sending nmea: %s",
627 g_string_append_len(string
,
630 g_string_append_c(string
, '\r');
631 g_string_append_c(string
, '\n');
634 INFO("Sending nmea: %s",
636 g_string_append_len(string
,
639 g_string_append_c(string
, '\r');
640 g_string_append_c(string
, '\n');
642 if (nmea_gsv
[0]->len
) {
643 INFO("Sending nmea: %s",
645 g_string_append_len(string
,
648 g_string_append_c(string
, '\r');
649 g_string_append_c(string
, '\n');
651 if (nmea_gsv
[1]->len
) {
652 INFO("Sending nmea: %s",
654 g_string_append_len(string
,
657 g_string_append_c(string
, '\r');
658 g_string_append_c(string
, '\n');
660 if (nmea_gsv
[2]->len
) {
661 INFO("Sending nmea: %s",
663 g_string_append_len(string
,
666 g_string_append_c(string
, '\r');
667 g_string_append_c(string
, '\n');
670 INFO("Sending nmea: %s",
672 g_string_append_len(string
,
675 g_string_append_c(string
, '\r');
676 g_string_append_c(string
, '\n');
679 INFO("Sending nmea: %s",
681 g_string_append_len(string
,
684 g_string_append_c(string
, '\r');
685 g_string_append_c(string
, '\n');
688 INFO("Sending nmea: %s",
690 g_string_append_len(string
,
693 g_string_append_c(string
, '\r');
694 g_string_append_c(string
, '\n');
698 send_to_client(client
, string
->str
, string
->len
);
703 g_string_free(string
, TRUE
);
712 queue_send_nmea_to_clients(void)
720 g_idle_add(send_nmea_to_clients
, NULL
);
723 /******************************************************************************/
726 add_sats(GString
*string
)
730 if (satellite_satellitec
== 0) {
731 g_string_append(string
, ",Y=?");
735 g_string_append(string
, ",Y=-");
737 if (time_seconds
<= 0) {
738 g_string_append(string
, " ? ");
740 g_string_append_printf(string
, " %d.000 ", time_seconds
);
743 count
= MIN(satellite_satellitec
, 12);
745 g_string_append_printf(string
, "%d:", count
);
747 for (i
= 0; i
< count
; i
++) {
748 g_string_append_printf(string
, "%d %d %d %d %d:",
749 satellite_satellitev
[i
].prn
,
750 satellite_satellitev
[i
].elevation
,
751 satellite_satellitev
[i
].azimuth
,
752 satellite_satellitev
[i
].snr
,
753 satellite_satellitev
[i
].used
);
757 /******************************************************************************/
760 send_sats_to_clients(gpointer data
)
765 for (string
= NULL
, l
= client_list
; l
; l
= l
->next
) {
766 struct client
*client
= l
->data
;
768 if (client
->watcher
) {
770 static GTimeVal timestamp
= { 0, 0 };
772 if (data
&& check_period(×tamp
, data
, 1)) {
776 g_get_current_time(×tamp
);
778 string
= g_string_sized_new(1024);
780 g_string_append(string
, "GPSD");
784 INFO("Sending sats: %s", string
->str
);
786 g_string_append_c(string
, '\r');
787 g_string_append_c(string
, '\n');
790 send_to_client(client
, string
->str
, string
->len
);
795 g_string_free(string
, TRUE
);
804 queue_send_sats_to_clients(void)
812 g_idle_add(send_sats_to_clients
, NULL
);
815 /******************************************************************************/
818 add_info(GString
*string
)
820 if (!device_connectionstatus
|| get_fixstatus() <= 1) {
821 g_string_append(string
, ",O=?");
825 g_string_append(string
, ",O=-");
827 if (time_seconds
<= 0) {
828 g_string_append_c(string
, ' ');
829 g_string_append_c(string
, '?');
831 g_string_append_printf(string
, " %d.000", time_seconds
);
834 g_string_append_c(string
, ' '); /* FIXME */
835 g_string_append_c(string
, '?');
837 if (!POSITION_LATITUDE_IS_VALID
) {
838 g_string_append_c(string
, ' ');
839 g_string_append_c(string
, '?');
841 g_string_append_printf(string
, " %.6f", position_latitude
);
843 if (!POSITION_LONGITUDE_IS_VALID
) {
844 g_string_append_c(string
, ' ');
845 g_string_append_c(string
, '?');
847 g_string_append_printf(string
, " %.6f", position_longitude
);
849 if (!POSITION_ALTITUDE_IS_VALID
) {
850 g_string_append_c(string
, ' ');
851 g_string_append_c(string
, '?');
853 g_string_append_printf(string
, " %.2f", position_altitude
);
855 if (!ACCURACY_HDOP_IS_VALID
) {
856 g_string_append_c(string
, ' ');
857 g_string_append_c(string
, '?');
859 g_string_append_printf(string
, " %.2f", accuracy_hdop
);
861 if (!ACCURACY_VDOP_IS_VALID
) {
862 g_string_append_c(string
, ' ');
863 g_string_append_c(string
, '?');
865 g_string_append_printf(string
, " %.2f", accuracy_vdop
);
867 if (!COURSE_DIRECTION_IS_VALID
) {
868 g_string_append_c(string
, ' ');
869 g_string_append_c(string
, '?');
871 g_string_append_printf(string
, " %.4f", course_direction
);
873 if (!COURSE_SPEED_IS_VALID
) {
874 g_string_append_c(string
, ' ');
875 g_string_append_c(string
, '?');
877 g_string_append_printf(string
, " %.3f",
878 course_speed
* KNOTS_TO_MPS
);
880 if (!COURSE_CLIMB_IS_VALID
) {
881 g_string_append_c(string
, ' ');
882 g_string_append_c(string
, '?');
884 g_string_append_printf(string
, " %.3f", course_climb
);
887 g_string_append(string
, " ? ? ?"); /* FIXME */
889 g_string_append_printf(string
, " %d", get_fixstatus());
892 /******************************************************************************/
895 send_info_to_clients(gpointer data
)
900 for (string
= NULL
, l
= client_list
; l
; l
= l
->next
) {
901 struct client
*client
= l
->data
;
903 if (client
->watcher
) {
905 static GTimeVal timestamp
= { 0, 0 };
907 if (data
&& check_period(×tamp
, data
, 1)) {
911 g_get_current_time(×tamp
);
913 string
= g_string_sized_new(1024);
915 g_string_append(string
, "GPSD");
919 INFO("Sending info: %s", string
->str
);
921 g_string_append_c(string
, '\r');
922 g_string_append_c(string
, '\n');
925 send_to_client(client
, string
->str
, string
->len
);
930 g_string_free(string
, TRUE
);
939 queue_send_info_to_clients(void)
947 g_idle_add(send_info_to_clients
, NULL
);
950 /******************************************************************************/
953 connection_status_changed(
955 gboolean connectionstatus
,
959 device_connectionstatus
= connectionstatus
;
961 INFO(GYPSY_DEVICE
": ConnectionStatusChanged(connectionstatus=%s)",
962 device_connectionstatus
? "TRUE" : "FALSE");
974 device_fixstatus
= fixstatus
;
976 switch (device_fixstatus
) {
991 INFO(GYPSY_DEVICE
": FixStatusChanged(fixstatus=%s)", str
);
993 g_string_truncate(nmea_gga
, 0);
994 g_string_truncate(nmea_gsa
, 0);
995 g_string_truncate(nmea_rmc
, 0);
996 g_string_truncate(nmea_gll
, 0);
998 queue_send_nmea_to_clients();
999 queue_send_info_to_clients();
1009 time_seconds
= seconds
;
1011 INFO(GYPSY_TIME
": TimeChanged(seconds=%d)", time_seconds
);
1013 g_string_truncate(nmea_gga
, 0);
1014 g_string_truncate(nmea_rmc
, 0);
1015 g_string_truncate(nmea_gll
, 0);
1017 queue_send_nmea_to_clients();
1018 queue_send_info_to_clients();
1032 position_fields
= fields
;
1033 position_timestamp
= timestamp
;
1034 position_latitude
= latitude
;
1035 position_longitude
= longitude
;
1036 position_altitude
= altitude
;
1038 INFO(GYPSY_POSITION
": PositionChanged(timestamp=%d, latitude=%f, longitude=%f, altitude=%f)",
1040 POSITION_LATITUDE_IS_VALID
? position_latitude
: NAN
,
1041 POSITION_LONGITUDE_IS_VALID
? position_longitude
: NAN
,
1042 POSITION_ALTITUDE_IS_VALID
? position_altitude
: NAN
);
1044 g_string_truncate(nmea_gga
, 0);
1045 g_string_truncate(nmea_rmc
, 0);
1046 g_string_truncate(nmea_gll
, 0);
1048 queue_send_nmea_to_clients();
1049 queue_send_info_to_clients();
1062 accuracy_fields
= fields
;
1063 accuracy_pdop
= pdop
;
1064 accuracy_hdop
= hdop
;
1065 accuracy_vdop
= vdop
;
1067 INFO(GYPSY_ACCURACY
": AccuracyChanged(pdop=%f, hdop=%f, vdop=%f)",
1068 ACCURACY_PDOP_IS_VALID
? accuracy_pdop
: NAN
,
1069 ACCURACY_HDOP_IS_VALID
? accuracy_hdop
: NAN
,
1070 ACCURACY_VDOP_IS_VALID
? accuracy_vdop
: NAN
);
1072 g_string_truncate(nmea_gga
, 0);
1073 g_string_truncate(nmea_gsa
, 0);
1075 queue_send_nmea_to_clients();
1076 queue_send_info_to_clients();
1090 course_fields
= fields
;
1091 course_timestamp
= timestamp
;
1092 course_speed
= speed
;
1093 course_direction
= direction
;
1094 course_climb
= climb
;
1096 INFO(GYPSY_COURSE
": CourseChanged(timestamp=%d, speed=%f, direction=%f, climb=%f)",
1098 COURSE_SPEED_IS_VALID
? course_speed
: NAN
,
1099 COURSE_DIRECTION_IS_VALID
? course_direction
: NAN
,
1100 COURSE_CLIMB_IS_VALID
? course_climb
: NAN
);
1102 g_string_truncate(nmea_rmc
, 0);
1103 g_string_truncate(nmea_vtg
, 0);
1105 queue_send_nmea_to_clients();
1106 queue_send_info_to_clients();
1112 GPtrArray
*satellites
,
1119 satellite_satellitec
= 0;
1121 satellite_satellitec
= MIN(SATELLITEC_MAX
, satellites
->len
);
1124 for (i
= 0; i
< satellite_satellitec
; i
++) {
1125 struct satellite
*sat
;
1128 sat
= satellite_satellitev
+ i
;
1129 val
= satellites
->pdata
[i
];
1131 sat
->prn
= g_value_get_uint(g_value_array_get_nth(val
, 0));
1132 sat
->used
= g_value_get_boolean(g_value_array_get_nth(val
, 1));
1133 sat
->elevation
= g_value_get_uint(g_value_array_get_nth(val
, 2));
1134 sat
->azimuth
= g_value_get_uint(g_value_array_get_nth(val
, 3));
1135 sat
->snr
= g_value_get_uint(g_value_array_get_nth(val
, 4));
1137 INFO(GYPSY_SATELLITE
": SatellitesChanged(index=%d, prn=%u, used=%s, elevation=%u, azimuth=%u, snr=%u)",
1140 sat
->used
? "TRUE" : "FALSE",
1146 g_string_truncate(nmea_gga
, 0);
1147 g_string_truncate(nmea_gsa
, 0);
1148 g_string_truncate(nmea_gsv
[0], 0);
1149 g_string_truncate(nmea_gsv
[1], 0);
1150 g_string_truncate(nmea_gsv
[2], 0);
1152 queue_send_nmea_to_clients();
1153 queue_send_sats_to_clients();
1156 /******************************************************************************/
1159 get_connection_status_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1161 GError
*error
= NULL
;
1162 gboolean connectionstatus
= FALSE
;
1164 DEBUG(GYPSY_DEVICE
": GetConnectionStatus: Notify");
1166 dbus_g_proxy_end_call(proxy
, call
, &error
,
1167 G_TYPE_BOOLEAN
, &connectionstatus
,
1171 WARNING(GYPSY_DEVICE
": GetConnectionStatus: %s", error
->message
);
1172 g_error_free(error
);
1174 DEBUG(GYPSY_DEVICE
": GetConnectionStatus: OK");
1176 if (proxy
== device_proxy
) {
1177 connection_status_changed(NULL
, connectionstatus
, NULL
);
1183 get_fix_status_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1185 GError
*error
= NULL
;
1188 DEBUG(GYPSY_DEVICE
": GetFixStatus: Notify");
1190 dbus_g_proxy_end_call(proxy
, call
, &error
,
1191 G_TYPE_INT
, &fixstatus
,
1195 WARNING(GYPSY_DEVICE
": GetFixStatus: %s", error
->message
);
1196 g_error_free(error
);
1198 DEBUG(GYPSY_DEVICE
": GetFixStatus: OK");
1200 if (proxy
== device_proxy
) {
1201 fix_status_changed(NULL
, fixstatus
, NULL
);
1207 get_time_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1209 GError
*error
= NULL
;
1212 DEBUG(GYPSY_TIME
": GetTime: Notify");
1214 dbus_g_proxy_end_call(proxy
, call
, &error
,
1215 G_TYPE_INT
, &seconds
,
1219 WARNING(GYPSY_TIME
": GetTime: %s", error
->message
);
1220 g_error_free(error
);
1222 DEBUG(GYPSY_TIME
": GetTime: OK");
1224 if (proxy
== time_proxy
) {
1225 time_changed(NULL
, seconds
, NULL
);
1231 get_position_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1233 GError
*error
= NULL
;
1234 int fields
= 0, timestamp
= 0;
1235 double latitude
= 0.0, longitude
= 0.0, altitude
= 0.0;
1237 DEBUG(GYPSY_POSITION
": GetPosition: Notify");
1239 dbus_g_proxy_end_call(proxy
, call
, &error
,
1240 G_TYPE_INT
, &fields
,
1241 G_TYPE_INT
, ×tamp
,
1242 G_TYPE_DOUBLE
, &latitude
,
1243 G_TYPE_DOUBLE
, &longitude
,
1244 G_TYPE_DOUBLE
, &altitude
,
1248 WARNING(GYPSY_POSITION
": GetPosition: %s", error
->message
);
1249 g_error_free(error
);
1251 DEBUG(GYPSY_POSITION
": GetPosition: OK");
1253 if (proxy
== position_proxy
) {
1254 position_changed(NULL
, fields
, timestamp
, latitude
,
1255 longitude
, altitude
, NULL
);
1261 get_accuracy_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1263 GError
*error
= NULL
;
1265 double pdop
= 0.0, hdop
= 0.0, vdop
= 0.0;
1267 DEBUG(GYPSY_ACCURACY
": GetAccuracy: Notify");
1269 dbus_g_proxy_end_call(proxy
, call
, &error
,
1270 G_TYPE_INT
, &fields
,
1271 G_TYPE_DOUBLE
, &pdop
,
1272 G_TYPE_DOUBLE
, &hdop
,
1273 G_TYPE_DOUBLE
, &vdop
,
1277 WARNING(GYPSY_ACCURACY
": GetAccuracy: %s", error
->message
);
1278 g_error_free(error
);
1280 DEBUG(GYPSY_ACCURACY
": GetAccuracy: OK");
1282 if (proxy
== accuracy_proxy
) {
1283 accuracy_changed(NULL
, fields
, pdop
, hdop
, vdop
, NULL
);
1289 get_course_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1291 GError
*error
= NULL
;
1292 int fields
= 0, timestamp
= 0;
1293 double speed
= 0.0, direction
= 0.0, climb
= 0.0;
1295 DEBUG(GYPSY_COURSE
": GetCourse: Notify");
1297 dbus_g_proxy_end_call(proxy
, call
, &error
,
1298 G_TYPE_INT
, &fields
,
1299 G_TYPE_INT
, ×tamp
,
1300 G_TYPE_DOUBLE
, &speed
,
1301 G_TYPE_DOUBLE
, &direction
,
1302 G_TYPE_DOUBLE
, &climb
,
1306 WARNING(GYPSY_COURSE
": GetCourse: %s", error
->message
);
1307 g_error_free(error
);
1309 DEBUG(GYPSY_COURSE
": GetCourse: OK");
1311 if (proxy
== course_proxy
) {
1312 course_changed(NULL
, fields
, timestamp
, speed
,
1313 direction
, climb
, NULL
);
1319 get_satellites_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1321 GError
*error
= NULL
;
1322 GPtrArray
*satellites
= NULL
;
1324 DEBUG(GYPSY_SATELLITE
": GetSatellites: Notify");
1326 dbus_g_proxy_end_call(proxy
, call
, &error
,
1327 dbus_g_type_get_collection("GPtrArray",
1328 dbus_g_type_get_struct("GValueArray",
1339 WARNING(GYPSY_SATELLITE
": GetSatellites: %s", error
->message
);
1340 g_error_free(error
);
1342 DEBUG(GYPSY_SATELLITE
": GetSatellites: OK");
1344 if (proxy
== satellite_proxy
) {
1345 satellites_changed(NULL
, satellites
, NULL
);
1350 /******************************************************************************/
1353 device_start_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1355 GError
*error
= NULL
;
1357 DEBUG(GYPSY_DEVICE
": Start: Notify");
1359 dbus_g_proxy_end_call(proxy
, call
, &error
, G_TYPE_INVALID
);
1362 WARNING(GYPSY_DEVICE
": Start: %s", error
->message
);
1363 g_error_free(error
);
1364 gypsy_device_start_failed
= TRUE
;
1366 DEBUG(GYPSY_DEVICE
": Start: OK");
1367 gypsy_device_start_failed
= FALSE
;
1370 DEBUG(GYPSY_DEVICE
": GetConnectionStatus");
1371 dbus_g_proxy_begin_call(device_proxy
, "GetConnectionStatus",
1372 get_connection_status_notify
, NULL
, NULL
,
1375 DEBUG(GYPSY_DEVICE
": GetFixStatus");
1376 dbus_g_proxy_begin_call(device_proxy
, "GetFixStatus",
1377 get_fix_status_notify
, NULL
, NULL
,
1382 DEBUG(GYPSY_TIME
": GetTime");
1383 dbus_g_proxy_begin_call(time_proxy
, "GetTime",
1384 get_time_notify
, NULL
, NULL
,
1388 if (position_proxy
) {
1389 DEBUG(GYPSY_POSITION
": GetPosition");
1390 dbus_g_proxy_begin_call(position_proxy
, "GetPosition",
1391 get_position_notify
, NULL
, NULL
,
1395 if (accuracy_proxy
) {
1396 DEBUG(GYPSY_ACCURACY
": GetAccuracy");
1397 dbus_g_proxy_begin_call(accuracy_proxy
, "GetAccuracy",
1398 get_accuracy_notify
, NULL
, NULL
,
1403 DEBUG(GYPSY_COURSE
": GetCourse");
1404 dbus_g_proxy_begin_call(course_proxy
, "GetCourse",
1405 get_course_notify
, NULL
, NULL
,
1409 if (satellite_proxy
) {
1410 DEBUG(GYPSY_SATELLITE
": GetSatellites");
1411 dbus_g_proxy_begin_call(satellite_proxy
, "GetSatellites",
1412 get_satellites_notify
, NULL
, NULL
,
1418 /******************************************************************************/
1423 if (!gypsy_device_path
) {
1424 WARNING("No device, not starting");
1428 gypsy_device_start_failed
= FALSE
;
1431 device_proxy
= dbus_g_proxy_new_for_name(connection
,
1432 gypsy_service
, gypsy_device_path
, GYPSY_DEVICE
);
1434 DEBUG(GYPSY_DEVICE
": Start");
1435 dbus_g_proxy_begin_call(device_proxy
, "Start",
1436 device_start_notify
, NULL
, NULL
,
1439 dbus_g_proxy_add_signal(device_proxy
, "ConnectionStatusChanged",
1442 dbus_g_proxy_connect_signal(device_proxy
, "ConnectionStatusChanged",
1443 G_CALLBACK(connection_status_changed
), NULL
, NULL
);
1445 dbus_g_proxy_add_signal(device_proxy
, "FixStatusChanged",
1448 dbus_g_proxy_connect_signal(device_proxy
, "FixStatusChanged",
1449 G_CALLBACK(fix_status_changed
), NULL
, NULL
);
1452 time_proxy
= dbus_g_proxy_new_for_name(connection
,
1453 gypsy_service
, gypsy_device_path
, GYPSY_TIME
);
1455 dbus_g_proxy_add_signal(time_proxy
, "TimeChanged",
1458 dbus_g_proxy_connect_signal(time_proxy
, "TimeChanged",
1459 G_CALLBACK(time_changed
), NULL
, NULL
);
1462 position_proxy
= dbus_g_proxy_new_for_name(connection
,
1463 gypsy_service
, gypsy_device_path
, GYPSY_POSITION
);
1465 dbus_g_proxy_add_signal(position_proxy
, "PositionChanged",
1472 dbus_g_proxy_connect_signal(position_proxy
, "PositionChanged",
1473 G_CALLBACK(position_changed
), NULL
, NULL
);
1476 accuracy_proxy
= dbus_g_proxy_new_for_name(connection
,
1477 gypsy_service
, gypsy_device_path
, GYPSY_ACCURACY
);
1479 dbus_g_proxy_add_signal(accuracy_proxy
, "AccuracyChanged",
1485 dbus_g_proxy_connect_signal(accuracy_proxy
, "AccuracyChanged",
1486 G_CALLBACK(accuracy_changed
), NULL
, NULL
);
1489 course_proxy
= dbus_g_proxy_new_for_name(connection
,
1490 gypsy_service
, gypsy_device_path
, GYPSY_COURSE
);
1492 dbus_g_proxy_add_signal(course_proxy
, "CourseChanged",
1499 dbus_g_proxy_connect_signal(course_proxy
, "CourseChanged",
1500 G_CALLBACK(course_changed
), NULL
, NULL
);
1503 satellite_proxy
= dbus_g_proxy_new_for_name(connection
,
1504 gypsy_service
, gypsy_device_path
, GYPSY_SATELLITE
);
1506 dbus_g_proxy_add_signal(satellite_proxy
, "SatellitesChanged",
1507 dbus_g_type_get_collection("GPtrArray",
1508 dbus_g_type_get_struct("GValueArray",
1516 dbus_g_proxy_connect_signal(satellite_proxy
, "SatellitesChanged",
1517 G_CALLBACK(satellites_changed
), NULL
, NULL
);
1520 /******************************************************************************/
1523 device_stop_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1525 GError
*error
= NULL
;
1527 DEBUG(GYPSY_DEVICE
": Stop: Notify");
1529 dbus_g_proxy_end_call(proxy
, call
, &error
, G_TYPE_INVALID
);
1532 WARNING(GYPSY_DEVICE
": Stop: %s", error
->message
);
1533 g_error_free(error
);
1535 DEBUG(GYPSY_DEVICE
": Stop: OK");
1542 if (!gypsy_device_path
) {
1543 WARNING("No device, not stopping");
1548 if (gypsy_device_start_failed
) {
1549 gypsy_device_start_failed
= FALSE
;
1551 DEBUG(GYPSY_DEVICE
": Stop");
1552 dbus_g_proxy_begin_call(device_proxy
, "Stop",
1553 device_stop_notify
, NULL
, NULL
,
1557 dbus_g_proxy_disconnect_signal(device_proxy
, "ConnectionStatusChanged",
1558 G_CALLBACK(connection_status_changed
), NULL
);
1559 dbus_g_proxy_disconnect_signal(device_proxy
, "FixStatusChanged",
1560 G_CALLBACK(fix_status_changed
), NULL
);
1561 g_object_unref(G_OBJECT(device_proxy
));
1562 device_proxy
= NULL
;
1563 device_connectionstatus
= FALSE
;
1564 device_fixstatus
= 0;
1567 dbus_g_proxy_disconnect_signal(time_proxy
, "TimeChanged",
1568 G_CALLBACK(time_changed
), NULL
);
1569 g_object_unref(G_OBJECT(time_proxy
));
1574 dbus_g_proxy_disconnect_signal(position_proxy
, "PositionChanged",
1575 G_CALLBACK(position_changed
), NULL
);
1576 g_object_unref(G_OBJECT(position_proxy
));
1577 position_proxy
= NULL
;
1578 position_fields
= 0;
1579 position_timestamp
= 0;
1580 position_latitude
= 0.0;
1581 position_longitude
= 0.0;
1582 position_altitude
= 0.0;
1585 dbus_g_proxy_disconnect_signal(accuracy_proxy
, "AccuracyChanged",
1586 G_CALLBACK(accuracy_changed
), NULL
);
1587 g_object_unref(G_OBJECT(accuracy_proxy
));
1588 accuracy_proxy
= NULL
;
1589 accuracy_fields
= 0;
1590 accuracy_pdop
= 0.0;
1591 accuracy_hdop
= 0.0;
1592 accuracy_vdop
= 0.0;
1595 dbus_g_proxy_disconnect_signal(course_proxy
, "CourseChanged",
1596 G_CALLBACK(course_changed
), NULL
);
1597 g_object_unref(G_OBJECT(course_proxy
));
1598 course_proxy
= NULL
;
1600 course_timestamp
= 0;
1602 course_direction
= 0.0;
1606 dbus_g_proxy_disconnect_signal(satellite_proxy
, "SatellitesChanged",
1607 G_CALLBACK(satellites_changed
), NULL
);
1608 g_object_unref(G_OBJECT(satellite_proxy
));
1609 satellite_proxy
= NULL
;
1610 satellite_satellitec
= 0;
1613 /******************************************************************************/
1616 server_create_notify(DBusGProxy
*proxy
, DBusGProxyCall
*call
, gpointer data
)
1618 GError
*error
= NULL
;
1619 const char *path
= NULL
;
1621 DEBUG(GYPSY_SERVER
": Create: Notify");
1623 dbus_g_proxy_end_call(proxy
, call
, &error
,
1624 DBUS_TYPE_G_OBJECT_PATH
, &path
,
1628 WARNING(GYPSY_SERVER
": Create: %s", error
->message
);
1629 g_error_free(error
);
1630 gypsy_device_create_failed
= TRUE
;
1631 gypsy_device_path
= NULL
;
1633 DEBUG(GYPSY_SERVER
": Create: OK: %s", path
);
1634 gypsy_device_create_failed
= FALSE
;
1635 gypsy_device_path
= g_strdup(path
);
1637 if (client_list
|| nowait
) {
1646 gypsy_device_create_failed
= FALSE
;
1648 DEBUG(GYPSY_SERVER
": Create");
1649 dbus_g_proxy_begin_call(server_proxy
, "Create",
1650 server_create_notify
, NULL
, NULL
,
1651 G_TYPE_STRING
, gypsy_device
,
1655 /******************************************************************************/
1666 INFO("org.freedesktop.DBus: NameOwnerChanged(name=%s, prev=%s, new=%s)",
1669 if (name
&& !strcmp(name
, gypsy_service
)) {
1670 if (prev
&& strlen(prev
) > 0) {
1671 g_free(gypsy_device_path
);
1673 if (new && strlen(new) > 0) {
1676 gypsy_device_path
= NULL
;
1680 /******************************************************************************/
1683 timeout_handler(gpointer data
)
1685 if (!client_list
&& !nowait
) {
1686 DEBUG("Timeout: no client: removing timeout handler");
1687 timeout_handler_registered
= FALSE
;
1690 if (gypsy_device_create_failed
) {
1691 WARNING("Timeout: no gypsy device created");
1693 } else if (!gypsy_device_path
) {
1694 WARNING("Timeout: no gypsy device available");
1695 } else if (gypsy_device_start_failed
) {
1696 WARNING("Timeout: gypsy device not started");
1697 DEBUG(GYPSY_DEVICE
": Start");
1698 dbus_g_proxy_begin_call(device_proxy
, "Start",
1699 device_start_notify
, NULL
, NULL
,
1701 } else if (!device_connectionstatus
) {
1702 WARNING("Timeout: device started but not connected");
1706 DEBUG("Timeout: sending data to clients");
1708 g_get_current_time(&tv
);
1710 send_info_to_clients(&tv
);
1711 send_sats_to_clients(&tv
);
1712 send_nmea_to_clients(&tv
);
1718 /******************************************************************************/
1721 marshal_VOID__STRING_STRING_STRING(
1723 GValue
*return_value G_GNUC_UNUSED
,
1724 guint n_param_values
,
1725 const GValue
*param_values
,
1726 gpointer invocation_hint G_GNUC_UNUSED
,
1727 gpointer marshal_data
1730 typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING
)(
1737 GMarshalFunc_VOID__STRING_STRING_STRING callback
;
1738 GCClosure
*cc
= (GCClosure
*) closure
;
1739 gpointer data1
, data2
;
1741 g_return_if_fail (n_param_values
== 4);
1743 if (G_CCLOSURE_SWAP_DATA(closure
)) {
1744 data1
= closure
->data
;
1745 data2
= g_value_peek_pointer(param_values
+ 0);
1747 data1
= g_value_peek_pointer(param_values
+ 0);
1748 data2
= closure
->data
;
1751 callback
= (GMarshalFunc_VOID__STRING_STRING_STRING
) (
1752 marshal_data
? marshal_data
: cc
->callback
);
1755 (const gchar
*) g_value_get_string(param_values
+ 1),
1756 (const gchar
*) g_value_get_string(param_values
+ 2),
1757 (const gchar
*) g_value_get_string(param_values
+ 3),
1762 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE(
1764 GValue
*return_value G_GNUC_UNUSED
,
1765 guint n_param_values
,
1766 const GValue
*param_values
,
1767 gpointer invocation_hint G_GNUC_UNUSED
,
1768 gpointer marshal_data
1771 typedef void (*GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
)(
1780 GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE callback
;
1781 GCClosure
*cc
= (GCClosure
*) closure
;
1782 gpointer data1
, data2
;
1784 g_return_if_fail(n_param_values
== 6);
1786 if (G_CCLOSURE_SWAP_DATA(closure
)) {
1787 data1
= closure
->data
;
1788 data2
= g_value_peek_pointer(param_values
+ 0);
1790 data1
= g_value_peek_pointer(param_values
+ 0);
1791 data2
= closure
->data
;
1794 callback
= (GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
) (
1795 marshal_data
? marshal_data
: cc
->callback
);
1798 g_value_get_int(param_values
+ 1),
1799 g_value_get_int(param_values
+ 2),
1800 g_value_get_double(param_values
+ 3),
1801 g_value_get_double(param_values
+ 4),
1802 g_value_get_double(param_values
+ 5),
1807 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE(
1809 GValue
*return_value G_GNUC_UNUSED
,
1810 guint n_param_values
,
1811 const GValue
*param_values
,
1812 gpointer invocation_hint G_GNUC_UNUSED
,
1813 gpointer marshal_data
1816 typedef void (*GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE
)(
1824 GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE callback
;
1825 GCClosure
*cc
= (GCClosure
*) closure
;
1826 gpointer data1
, data2
;
1828 g_return_if_fail(n_param_values
== 5);
1830 if (G_CCLOSURE_SWAP_DATA(closure
)) {
1831 data1
= closure
->data
;
1832 data2
= g_value_peek_pointer(param_values
+ 0);
1834 data1
= g_value_peek_pointer(param_values
+ 0);
1835 data2
= closure
->data
;
1838 callback
= (GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE
) (
1839 marshal_data
? marshal_data
: cc
->callback
);
1842 g_value_get_int(param_values
+ 1),
1843 g_value_get_double(param_values
+ 2),
1844 g_value_get_double(param_values
+ 3),
1845 g_value_get_double(param_values
+ 4),
1849 /******************************************************************************/
1852 read_from_client(GIOChannel
*source
, GIOCondition condition
, gpointer data
)
1854 struct client
*client
;
1856 gsize len
= sizeof(buf
);
1863 if (condition
!= G_IO_IN
) {
1864 shutdown_client(client
);
1867 if (!client
->channel
) {
1868 MESSAGE("Removing client");
1870 client_list
= g_list_remove(client_list
, client
);
1872 g_io_channel_unref(source
);
1874 if (!client_list
&& !nowait
) {
1881 status
= g_io_channel_read_chars(source
, buf
, len
- 2, &len
, NULL
);
1883 if ((status
!= G_IO_STATUS_NORMAL
) || (len
< 1)) {
1884 shutdown_client(client
);
1888 if (buf
[len
- 1] != '\n') {
1895 reply
= g_string_sized_new(128);
1896 g_string_assign(reply
, "GPSD");
1901 switch (toupper(*p
++)) {
1903 if (!POSITION_ALTITUDE_IS_VALID
) {
1904 g_string_append(reply
, ",A=?");
1906 g_string_append_printf(reply
, ",A=%.3f",
1911 g_string_append(reply
, ",B=?");
1914 g_string_append(reply
, ",C=1.00"); /* FIXME */
1917 if (time_seconds
<= 0) {
1918 g_string_append(reply
, ",D=?");
1923 seconds
= time_seconds
;
1924 tm
= gmtime(&seconds
);
1926 g_string_append_printf(reply
,
1927 ",D=%04d-%02d-%02dT%02d:%02d:%02d.00Z",
1928 tm
->tm_year
+ 1900, tm
->tm_mon
+ 1,
1929 tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
,
1934 g_string_append(reply
, ",E=");
1936 if (!ACCURACY_PDOP_IS_VALID
) {
1937 g_string_append(reply
, "?");
1939 g_string_append_printf(reply
, "%.2f",
1942 if (!ACCURACY_HDOP_IS_VALID
) {
1943 g_string_append(reply
, " ?");
1945 g_string_append_printf(reply
, " %.2f",
1948 if (!ACCURACY_VDOP_IS_VALID
) {
1949 g_string_append(reply
, " ?");
1951 g_string_append_printf(reply
, " %.2f",
1957 while (isprint(*p
) && !isspace(*p
)) {
1961 g_string_append(reply
, ",F=gypsy");
1965 p
+= strcspn(p
, ",\r\n");
1967 g_string_append(reply
, ",G=GPS");
1970 g_string_append(reply
, ",I=gypsy");
1976 if (*p
== '1' || *p
== '+') {
1978 g_string_append(reply
, ",J=1");
1980 if (*p
== '0' || *p
== '-') {
1983 g_string_append(reply
, ",J=0");
1987 g_string_append(reply
, ",K=1 gypsy");
1990 g_string_append(reply
, ",L=3 " VERSION
1991 " abcdefgijklmnopqrstuvwxyz");
1994 g_string_append_printf(reply
, ",M=%d",
1998 g_string_append(reply
, ",N=0");
2004 if (!POSITION_LATITUDE_IS_VALID
2005 || !POSITION_LONGITUDE_IS_VALID
) {
2006 g_string_append(reply
, ",P=?");
2008 g_string_append_printf(reply
, ",P=%.6f %.6f",
2009 position_latitude
, position_longitude
);
2013 if (!ACCURACY_PDOP_IS_VALID
2014 && !ACCURACY_HDOP_IS_VALID
2015 && !ACCURACY_VDOP_IS_VALID
) {
2016 g_string_append(reply
, ",Q=?");
2020 for (i
= 0, used
= 0; i
< satellite_satellitec
; i
++) {
2021 if (satellite_satellitev
[i
].used
) {
2026 g_string_append_printf(reply
,
2027 ",Q=%d %.2f %.2f %.2f %.2f %.2f", used
,
2028 ACCURACY_PDOP_IS_VALID
? accuracy_pdop
: 0.0,
2029 ACCURACY_HDOP_IS_VALID
? accuracy_hdop
: 0.0,
2030 ACCURACY_VDOP_IS_VALID
? accuracy_vdop
: 0.0,
2038 if (*p
== '2' || *p
== '1' || *p
== '+') {
2041 } else if (*p
== '0' || *p
== '-') {
2042 client
->raw
= FALSE
;
2045 client
->raw
= !client
->raw
;
2047 g_string_append_printf(reply
, ",R=%1d", client
->raw
);
2050 g_string_append_printf(reply
, ",S=%d",
2051 MAX(get_fixstatus() - 1, 0));
2054 if (!COURSE_DIRECTION_IS_VALID
) {
2055 g_string_append(reply
, ",T=?");
2057 g_string_append_printf(reply
, ",T=%.4f",
2062 if (!COURSE_CLIMB_IS_VALID
) {
2063 g_string_append(reply
, ",U=?");
2065 g_string_append_printf(reply
, ",U=%.3f",
2070 if (!COURSE_SPEED_IS_VALID
) {
2071 g_string_append(reply
, ",V=?");
2073 g_string_append_printf(reply
, ",V=%.3f",
2074 course_speed
* KNOTS_TO_MPS
);
2081 if (*p
== '1' || *p
== '+') {
2082 client
->watcher
= TRUE
;
2084 } else if (*p
== '0' || *p
== '-') {
2085 client
->watcher
= FALSE
;
2088 client
->watcher
= !client
->watcher
;
2090 g_string_append_printf(reply
, ",W=%1d", client
->watcher
);
2093 if (time_seconds
<= 0) {
2094 g_string_append(reply
, ",X=?");
2096 g_string_append_printf(reply
, ",X=%d.000000",
2104 g_string_append(reply
, ",Z=?"); /* FIXME */
2107 g_string_append(reply
, ",$=?"); /* FIXME */
2118 g_string_append(reply
, "\r\n");
2119 send_to_client(client
, reply
->str
, reply
->len
);
2120 g_string_free(reply
, TRUE
);
2125 accept_new_client(GIOChannel
*source
, GIOCondition condition
, gpointer data
)
2127 struct sockaddr_in addr
;
2128 socklen_t len
= sizeof(addr
);
2129 struct client
*client
;
2132 MESSAGE("New client request");
2134 fd
= accept(g_io_channel_unix_get_fd(source
),
2135 (struct sockaddr
*) &addr
, &len
);
2138 ERROR("Cannot accept new connection: %s", strerror(errno
));
2141 client
= g_new0(struct client
, 1);
2144 ERROR("Cannot allocate memory");
2147 if (!timeout_handler_registered
) {
2148 timeout_handler_registered
= TRUE
;
2149 g_timeout_add(2000, timeout_handler
, NULL
);
2152 if (!client_list
&& !nowait
) {
2156 client_list
= g_list_prepend(client_list
, client
);
2158 client
->channel
= g_io_channel_unix_new(fd
);
2160 g_io_channel_set_flags(client
->channel
, G_IO_FLAG_NONBLOCK
, NULL
);
2161 g_io_channel_set_encoding(client
->channel
, NULL
, NULL
);
2162 g_io_channel_set_buffered(client
->channel
, FALSE
);
2164 g_io_add_watch(client
->channel
,
2165 G_IO_IN
| G_IO_PRI
| G_IO_ERR
| G_IO_HUP
| G_IO_NVAL
,
2166 read_from_client
, client
);
2172 init_tcp_service(const char *address
, const char *port
)
2174 struct addrinfo hints
, *l
, *list
= NULL
;
2175 int error
, errno_backup
= 0;
2176 gboolean ok
= FALSE
;
2178 memset(&hints
, 0, sizeof(hints
));
2179 hints
.ai_family
= AF_UNSPEC
;
2180 hints
.ai_socktype
= SOCK_STREAM
;
2181 hints
.ai_flags
= AI_PASSIVE
;
2183 if (address
&& !strlen(address
)) {
2187 if (!port
|| !strlen(port
)) {
2191 error
= getaddrinfo(address
, port
, &hints
, &list
);
2195 ERROR("Cannot get address info for address=%s, port=%s: %s",
2196 address
, port
, gai_strerror(error
));
2198 ERROR("Cannot get address info for port=%s: %s",
2199 port
, gai_strerror(error
));
2203 for (l
= list
; l
; l
= l
->ai_next
) {
2204 GIOChannel
*channel
;
2207 fd
= socket(l
->ai_family
, l
->ai_socktype
, l
->ai_protocol
);
2210 errno_backup
= errno
;
2214 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
,
2215 (void *) &one
, sizeof(one
));
2217 if (bind(fd
, l
->ai_addr
, l
->ai_addrlen
) < 0) {
2218 errno_backup
= errno
;
2223 if (listen(fd
, 4) < 0) {
2224 errno_backup
= errno
;
2229 channel
= g_io_channel_unix_new(fd
);
2231 g_io_channel_set_encoding(channel
, NULL
, NULL
);
2232 g_io_channel_set_buffered(channel
, FALSE
);
2234 g_io_add_watch(channel
, G_IO_IN
| G_IO_PRI
| G_IO_HUP
| G_IO_ERR
,
2235 accept_new_client
, NULL
);
2242 ERROR("Cannot listen on address=%s, port=%s: %s",
2243 address
, port
, strerror(errno_backup
));
2245 ERROR("Cannot listen on port=%s: %s",
2246 port
, strerror(errno_backup
));
2255 /******************************************************************************/
2258 printerr_handler(const char *message
)
2261 syslog(LOG_USER
| LOG_INFO
, "%s", message
);
2263 fputs(message
, stderr
);
2270 GLogLevelFlags level
,
2271 const char *message
,
2275 const char *level_string
;
2277 switch (level
& G_LOG_LEVEL_MASK
) {
2278 case G_LOG_LEVEL_ERROR
:
2279 level_string
= "ERROR: ";
2281 case G_LOG_LEVEL_CRITICAL
:
2282 level_string
= "CRITICAL: ";
2284 case G_LOG_LEVEL_WARNING
:
2285 level_string
= "WARNING: ";
2287 case G_LOG_LEVEL_MESSAGE
:
2288 level_string
= "MESSAGE: ";
2290 case G_LOG_LEVEL_INFO
:
2291 level_string
= "INFO: ";
2293 case G_LOG_LEVEL_DEBUG
:
2294 level_string
= "DEBUG: ";
2303 syslog(LOG_USER
| LOG_INFO
, "%s: %s%s", domain
,
2304 level_string
, message
);
2306 syslog(LOG_USER
| LOG_INFO
, "%s%s",
2307 level_string
, message
);
2310 struct timeval tv
= { 0, 0 };
2315 gettimeofday(&tv
, NULL
);
2316 tm
= localtime(&tv
.tv_sec
);
2317 len
= strftime(buf
, sizeof(buf
), "%T", tm
);
2324 fprintf(stderr
, "%s.%06li %s: %s%s\n", buf
,
2325 (long) tv
.tv_usec
, domain
, level_string
,
2328 fprintf(stderr
, "%s.%06li %s%s\n", buf
,
2329 (long) tv
.tv_usec
, level_string
, message
);
2334 /******************************************************************************/
2340 Usage: "PACKAGE_NAME
" [-n] [-N] [-f device] [-P pidfile] [-D n] [-S port] [-h] [-V]\n\
2343 -n Don't wait for client connects to poll GPS\n\
2344 -N Don't go into background\n\
2345 -f device Set a GPS device name\n\
2346 -P pidfile Set file to record process ID\n\
2347 -D integer (default 0) Set debug level\n\
2348 -S integer (default 2947) Set port for daemon\n\
2349 -h Display help message and terminate\n\
2350 -V Emit version and exit\n");
2353 /******************************************************************************/
2356 main(int argc
, char **argv
)
2358 DBusGProxy
*proxy_dbus
= NULL
;
2359 GMainLoop
*loop
= NULL
;
2361 char *address
= NULL
;
2362 char *pid_file
= NULL
;
2363 gboolean foreground
= FALSE
;
2364 GError
*error
= NULL
;
2366 g_set_prgname(PACKAGE_NAME
);
2367 g_set_printerr_handler(printerr_handler
);
2368 g_log_set_default_handler(log_handler
, NULL
);
2374 option
= getopt(argc
, argv
, "F:D:S:bhNnP:VR:f:");
2384 WARNING("Not implemented: -%c", option
);
2387 switch (atoi(optarg
)) {
2389 log_level
= G_LOG_LEVEL_ERROR
2390 | G_LOG_LEVEL_CRITICAL
2391 | G_LOG_LEVEL_WARNING
;
2394 log_level
= G_LOG_LEVEL_ERROR
2395 | G_LOG_LEVEL_CRITICAL
2396 | G_LOG_LEVEL_WARNING
2397 | G_LOG_LEVEL_MESSAGE
;
2400 log_level
= G_LOG_LEVEL_ERROR
2401 | G_LOG_LEVEL_CRITICAL
2402 | G_LOG_LEVEL_WARNING
2403 | G_LOG_LEVEL_MESSAGE
2407 log_level
= G_LOG_LEVEL_ERROR
2408 | G_LOG_LEVEL_CRITICAL
2409 | G_LOG_LEVEL_WARNING
2410 | G_LOG_LEVEL_MESSAGE
2412 | G_LOG_LEVEL_DEBUG
;
2417 gypsy_device
= optarg
;
2423 port
= strrchr(optarg
, ':');
2440 printf(PACKAGE_NAME
" "VERSION
"\n");
2459 ERROR("Cannot fork: %s", strerror(errno
));
2460 } else if (pid
> 0) {
2464 openlog(PACKAGE_NAME
, LOG_PID
, LOG_USER
);
2470 fd
= open("/dev/null", O_RDWR
, 0);
2473 ERROR("Cannot open: /dev/null: %s", strerror(errno
));
2476 dup2(fd
, STDIN_FILENO
);
2477 dup2(fd
, STDOUT_FILENO
);
2478 dup2(fd
, STDERR_FILENO
);
2486 s
= getenv("FSO_GPSD_GYPSY_SERVICE");
2489 WARNING("Found environment variable: "
2490 "FSO_GPSD_GYPSY_SERVICE = %s", s
);
2491 gypsy_service
= g_strdup(s
);
2494 s
= getenv("FSO_GPSD_GYPSY_SERVER_PATH");
2497 WARNING("Found environment variable: "
2498 "FSO_GPSD_GYPSY_SERVER_PATH = %s", s
);
2499 gypsy_server_path
= g_strdup(s
);
2506 fp
= fopen(pid_file
, "w");
2509 ERROR("Cannot fopen: %s: %s", pid_file
, strerror(errno
));
2512 fprintf(fp
, "%u\n", (unsigned) getpid());
2518 loop
= g_main_loop_new(NULL
, FALSE
);
2520 connection
= dbus_g_bus_get(DBUS_BUS_SYSTEM
, &error
);
2523 ERROR("Failed to open connection to system bus: %s",
2527 dbus_g_object_register_marshaller(
2528 marshal_VOID__STRING_STRING_STRING
,
2534 dbus_g_object_register_marshaller(
2535 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE
,
2542 dbus_g_object_register_marshaller(
2543 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
,
2552 proxy_dbus
= dbus_g_proxy_new_for_name(connection
,
2553 "org.freedesktop.DBus", "/org/freedesktop/DBus",
2554 "org.freedesktop.DBus");
2556 server_proxy
= dbus_g_proxy_new_for_name(connection
,
2557 gypsy_service
, gypsy_server_path
, GYPSY_SERVER
);
2559 dbus_g_proxy_add_signal(proxy_dbus
, "NameOwnerChanged",
2564 dbus_g_proxy_connect_signal(proxy_dbus
, "NameOwnerChanged",
2565 G_CALLBACK(name_owner_changed
), NULL
, NULL
);
2569 nmea_gga
= g_string_sized_new(128);
2570 nmea_gsa
= g_string_sized_new(128);
2571 nmea_gsv
[0] = g_string_sized_new(128);
2572 nmea_gsv
[1] = g_string_sized_new(128);
2573 nmea_gsv
[2] = g_string_sized_new(128);
2574 nmea_rmc
= g_string_sized_new(128);
2575 nmea_gll
= g_string_sized_new(128);
2576 nmea_vtg
= g_string_sized_new(128);
2578 init_tcp_service(address
, port
);
2581 timeout_handler_registered
= TRUE
;
2582 g_timeout_add(2000, timeout_handler
, NULL
);
2585 g_main_loop_run(loop
);