1 /* fso-gpsd - a gpsd replacement which connects to 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>
32 #include <dbus/dbus.h>
33 #include <dbus/dbus-glib.h>
34 #include <glib-object.h>
39 /******************************************************************************/
41 #define NAME "fso-gpsd"
43 #define OUSAGED "org.freesmartphone.ousaged"
44 #define OGPSD "org.freesmartphone.ogpsd"
45 #define USAGE "/org/freesmartphone/Usage"
46 #define GYPSY "/org/freedesktop/Gypsy"
48 /******************************************************************************/
64 /******************************************************************************/
66 static gboolean nowait
= FALSE
;
68 static gboolean info_queued
= FALSE
;
69 static gboolean sats_queued
= FALSE
;
70 static gboolean nmea_queued
= FALSE
;
72 /******************************************************************************/
74 static GList
*client_list
= NULL
;
76 /******************************************************************************/
78 static DBusGConnection
*connection
;
79 static DBusGProxy
*proxy_usage
;
80 static DBusGProxy
*proxy_device
;
81 static DBusGProxy
*proxy_position
;
82 static DBusGProxy
*proxy_accuracy
;
83 static DBusGProxy
*proxy_course
;
84 static DBusGProxy
*proxy_satellite
;
85 static DBusGProxy
*proxy_time
;
87 /******************************************************************************/
89 static gboolean device_connectionstatus
;
90 static int device_fixstatus
; /* 0=INVALID, 1=NONE, 2=2D, 3=3D */
92 static int position_timestamp
;
93 static double position_latitude
;
94 static double position_longitude
;
95 static double position_altitude
;
97 static double accuracy_pdop
;
98 static double accuracy_hdop
;
99 static double accuracy_vdop
;
101 static int course_timestamp
;
102 static double course_speed
;
103 static double course_direction
;
104 static double course_climb
;
106 #define SATELLITEC_MAX 32
107 static struct satellite satellite_satellitev
[SATELLITEC_MAX
];
108 static unsigned satellite_satellitec
;
110 static int time_seconds
;
112 /******************************************************************************/
114 static GString
*nmea_gga
;
115 static GString
*nmea_gsa
;
116 static GString
*nmea_gsv
[3];
117 static GString
*nmea_rmc
;
118 static GString
*nmea_gll
;
119 static GString
*nmea_vtg
;
121 /******************************************************************************/
126 if (!isnan(position_latitude
) && !isnan(position_longitude
)) {
127 if (!isnan(position_altitude
)) {
128 return MIN(device_fixstatus
, 3);
130 return MIN(device_fixstatus
, 2);
133 return MIN(device_fixstatus
, 1);
137 /******************************************************************************/
143 remove_client(struct client
*client
)
145 g_message("Removing client");
147 client_list
= g_list_remove(client_list
, client
);
149 g_io_channel_shutdown(client
->channel
, FALSE
, NULL
);
150 g_io_channel_unref(client
->channel
);
154 if (!client_list
&& !nowait
) {
160 send_to_client(struct client
*client
, const char *string
, gsize len
)
165 /* TODO: check bytes_written */
166 status
= g_io_channel_write_chars(client
->channel
, string
,
167 len
, &bytes_written
, NULL
);
169 if (status
== G_IO_STATUS_ERROR
) {
170 remove_client(client
);
174 /******************************************************************************/
177 add_nmea_checksum(GString
*nmea
)
189 checksum
^= (int) *p
;
193 g_string_append_printf(nmea
, "*%02x\r\n", checksum
);
197 add_nmea_time(GString
*nmea
)
199 if (time_seconds
<= 0) {
200 g_string_append_c(nmea
, ',');
205 seconds
= time_seconds
;
206 tm
= gmtime(&seconds
);
208 g_string_append_printf(nmea
, ",%02d%02d%02d.00",
209 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
214 add_nmea_latitude(GString
*nmea
)
216 if (isnan(position_latitude
)) {
217 g_string_append(nmea
, ",,");
221 a
= fabs(position_latitude
);
224 g_string_append_printf(nmea
, ",%010.5f,%C",
225 (d
* 100.0) + ((a
- d
) * 60.0),
226 (position_latitude
> 0) ? 'N' : 'S');
231 add_nmea_longitude(GString
*nmea
)
233 if (isnan(position_longitude
)) {
234 g_string_append(nmea
, ",,");
238 a
= fabs(position_longitude
);
241 g_string_append_printf(nmea
, ",%011.5f,%C",
242 (d
* 100.0) + ((a
- d
) * 60.0),
243 (position_longitude
> 0) ? 'E' : 'W');
247 /******************************************************************************/
250 update_nmea_gga(void)
254 g_string_assign(nmea_gga
, "$GPGGA");
256 add_nmea_time(nmea_gga
);
258 add_nmea_latitude(nmea_gga
);
260 add_nmea_longitude(nmea_gga
);
262 g_string_append_printf(nmea_gga
, ",%1d", MAX(get_fixstatus() - 1, 0));
264 for (i
= 0, used
= 0; i
< satellite_satellitec
; i
++) {
265 if (satellite_satellitev
[i
].used
) {
270 g_string_append_printf(nmea_gga
, ",%02d", used
);
272 if (isnan(accuracy_hdop
)) {
273 g_string_append_c(nmea_gga
, ',');
275 g_string_append_printf(nmea_gga
, ",%04.2f", accuracy_hdop
);
278 if (isnan(position_altitude
)) {
279 g_string_append(nmea_gga
, ",,");
281 g_string_append_printf(nmea_gga
, ",%03.1f,M",
285 g_string_append(nmea_gga
, ",,"); /* FIXME */
287 g_string_append(nmea_gga
, ",,");
289 add_nmea_checksum(nmea_gga
);
293 update_nmea_gsa(void)
297 g_string_assign(nmea_gsa
, "$GPGSA");
299 g_string_append(nmea_gsa
, ",A");
301 g_string_append_printf(nmea_gsa
, ",%1d", MAX(get_fixstatus() - 1, 0));
303 for (i
= 0; i
< 12; i
++) {
304 if (i
< satellite_satellitec
) {
305 g_string_append_printf(nmea_gsa
, ",%02d",
306 satellite_satellitev
[i
].prn
);
308 g_string_append_c(nmea_gsa
, ',');
312 if (isnan(accuracy_pdop
)) {
313 g_string_append_c(nmea_gsa
, ',');
315 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_pdop
);
318 if (isnan(accuracy_hdop
)) {
319 g_string_append_c(nmea_gsa
, ',');
321 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_hdop
);
324 if (isnan(accuracy_vdop
)) {
325 g_string_append_c(nmea_gsa
, ',');
327 g_string_append_printf(nmea_gsa
, ",%04.2f", accuracy_vdop
);
330 add_nmea_checksum(nmea_gsa
);
334 update_nmea_gsv(void)
338 unsigned sentence_count
;
340 g_string_truncate(nmea_gsv
[0], 0);
341 g_string_truncate(nmea_gsv
[1], 0);
342 g_string_truncate(nmea_gsv
[2], 0);
344 if (satellite_satellitec
== 0) {
345 g_string_assign(nmea_gsv
[0], "$GPGSV,1,1,00*79\r\n");
349 sat_count
= MIN(satellite_satellitec
, 12);
350 sentence_count
= ((sat_count
- 1) / 4) + 1;
352 for (i
= 0; i
< sat_count
; i
++) {
353 int index_div
, index_mod
;
358 if (index_mod
== 0) {
359 g_string_append_printf(nmea_gsv
[index_div
],
360 "$GPGSV,%1d,%1d,%02d",
366 g_string_append_printf(nmea_gsv
[index_div
],
367 ",%02u,%02u,%03u,%02u",
368 satellite_satellitev
[i
].prn
,
369 satellite_satellitev
[i
].elevation
,
370 satellite_satellitev
[i
].azimuth
,
371 satellite_satellitev
[i
].snr
);
374 for (i
= 0; i
< 3; i
++) {
375 if (nmea_gsv
[i
]->len
> 0) {
376 add_nmea_checksum(nmea_gsv
[i
]);
382 update_nmea_rmc(void)
384 g_string_assign(nmea_rmc
, "$GPRMC");
386 add_nmea_time(nmea_rmc
);
388 if (get_fixstatus() > 1) {
389 g_string_append(nmea_rmc
, ",A");
391 g_string_append(nmea_rmc
, ",V");
394 add_nmea_latitude(nmea_rmc
);
396 add_nmea_longitude(nmea_rmc
);
398 if (isnan(course_speed
)) {
399 g_string_append_c(nmea_rmc
, ',');
401 g_string_append_printf(nmea_rmc
, ",%07.3f",
402 course_speed
/ KNOTS
);
405 if (isnan(course_direction
)) {
406 g_string_append_c(nmea_rmc
, ',');
408 g_string_append_printf(nmea_rmc
, ",%06.2f",
412 if (time_seconds
<= 0) {
413 g_string_append_c(nmea_rmc
, ',');
418 seconds
= time_seconds
;
419 tm
= gmtime(&seconds
);
421 g_string_append_printf(nmea_rmc
, ",%02d%02d%02d",
422 tm
->tm_mday
, tm
->tm_mon
+ 1, tm
->tm_year
% 100);
425 g_string_append(nmea_rmc
, ",,");
427 add_nmea_checksum(nmea_rmc
);
431 update_nmea_gll(void)
433 g_string_assign(nmea_gll
, "$GPGLL");
435 add_nmea_latitude(nmea_gll
);
437 add_nmea_longitude(nmea_gll
);
439 add_nmea_time(nmea_gll
);
441 if (get_fixstatus() > 1) {
442 g_string_append(nmea_gll
, ",A");
444 g_string_append(nmea_gll
, ",V");
447 add_nmea_checksum(nmea_gll
);
451 update_nmea_vtg(void)
453 g_string_assign(nmea_vtg
, "$GPVTG");
455 if (isnan(course_direction
)) {
456 g_string_append(nmea_vtg
, ",,");
458 g_string_append_printf(nmea_vtg
, ",%04.2f,T", course_direction
);
461 g_string_append(nmea_vtg
, ",,"); /* FIXME */
463 if (isnan(course_speed
)) {
464 g_string_append(nmea_vtg
, ",,,,");
466 g_string_append_printf(nmea_vtg
, ",%05.3f,N,%05.3f,K",
467 course_speed
/ KNOTS
, course_speed
);
470 add_nmea_checksum(nmea_vtg
);
473 /******************************************************************************/
476 send_nmea_to_clients(gpointer data
)
483 string
= g_string_sized_new(1024);
485 if (nmea_gga
->len
== 0) {
488 if (nmea_gsa
->len
== 0) {
491 if (nmea_gsv
[0]->len
== 0) {
494 if (nmea_rmc
->len
== 0) {
497 if (nmea_gll
->len
== 0) {
500 if (nmea_vtg
->len
== 0) {
504 g_string_append(string
, nmea_gga
->str
);
505 g_string_append(string
, nmea_gsa
->str
);
506 g_string_append(string
, nmea_gsv
[0]->str
);
507 g_string_append(string
, nmea_gsv
[1]->str
);
508 g_string_append(string
, nmea_gsv
[2]->str
);
509 g_string_append(string
, nmea_rmc
->str
);
510 g_string_append(string
, nmea_gll
->str
);
511 g_string_append(string
, nmea_vtg
->str
);
513 for (l
= client_list
; l
; l
= l
->next
) {
514 struct client
*client
= l
->data
;
517 send_to_client(client
, string
->str
, string
->len
);
521 g_string_free(string
, TRUE
);
527 queue_send_nmea_to_clients(void)
535 g_idle_add(send_nmea_to_clients
, NULL
);
538 /******************************************************************************/
541 add_sats(GString
*string
)
545 if (satellite_satellitec
== 0) {
546 g_string_append(string
, ",Y=?");
550 g_string_append(string
, ",Y=-");
552 if (time_seconds
<= 0) {
553 g_string_append(string
, " ? ");
555 g_string_append_printf(string
, " %d.000 ", time_seconds
);
558 count
= MIN(satellite_satellitec
, 12);
560 g_string_append_printf(string
, "%d:", count
);
562 for (i
= 0; i
< count
; i
++) {
563 g_string_append_printf(string
, "%d %d %d %d %d:",
564 satellite_satellitev
[i
].prn
,
565 satellite_satellitev
[i
].elevation
,
566 satellite_satellitev
[i
].azimuth
,
567 satellite_satellitev
[i
].snr
,
568 satellite_satellitev
[i
].used
);
572 /******************************************************************************/
575 send_sats_to_clients(gpointer data
)
582 string
= g_string_sized_new(1024);
584 g_string_append(string
, "GPSD");
588 g_string_append(string
, "\r\n");
590 for (l
= client_list
; l
; l
= l
->next
) {
591 struct client
*client
= l
->data
;
593 if (client
->watcher
) {
594 send_to_client(client
, string
->str
, string
->len
);
598 g_string_free(string
, TRUE
);
604 queue_send_sats_to_clients(void)
612 g_idle_add(send_sats_to_clients
, NULL
);
615 /******************************************************************************/
618 add_info(GString
*string
)
620 if (get_fixstatus() <= 1) {
621 g_string_append(string
, ",O=?");
625 g_string_append(string
, ",O=-");
627 if (time_seconds
<= 0) {
628 g_string_append(string
, " ?");
630 g_string_append_printf(string
, " %d.000", time_seconds
);
633 g_string_append(string
, " ?"); /* FIXME */
635 if (isnan(position_latitude
)) {
636 g_string_append(string
, " ?");
638 g_string_append_printf(string
, " %.6f", position_latitude
);
640 if (isnan(position_longitude
)) {
641 g_string_append(string
, " ?");
643 g_string_append_printf(string
, " %.6f", position_longitude
);
645 if (isnan(position_altitude
)) {
646 g_string_append(string
, " ?");
648 g_string_append_printf(string
, " %.2f", position_altitude
);
650 if (isnan(accuracy_hdop
)) {
651 g_string_append(string
, " ?");
653 g_string_append_printf(string
, " %.2f", accuracy_hdop
);
655 if (isnan(accuracy_vdop
)) {
656 g_string_append(string
, " ?");
658 g_string_append_printf(string
, " %.2f", accuracy_vdop
);
660 if (isnan(course_direction
)) {
661 g_string_append(string
, " ?");
663 g_string_append_printf(string
, " %.4f", course_direction
);
665 if (isnan(course_speed
)) {
666 g_string_append(string
, " ?");
668 g_string_append_printf(string
, " %.3f",
669 course_speed
/ (KNOTS
* 2));
671 if (isnan(course_climb
)) {
672 g_string_append(string
, " ?");
674 g_string_append_printf(string
, " %.3f", course_climb
);
677 g_string_append(string
, " ? ? ?"); /* FIXME */
679 g_string_append_printf(string
, " %d", get_fixstatus());
682 /******************************************************************************/
685 send_info_to_clients(gpointer data
)
692 string
= g_string_sized_new(1024);
694 g_string_append(string
, "GPSD");
698 g_string_append(string
, "\r\n");
700 for (l
= client_list
; l
; l
= l
->next
) {
701 struct client
*client
= l
->data
;
703 if (client
->watcher
) {
704 send_to_client(client
, string
->str
, string
->len
);
708 g_string_free(string
, TRUE
);
714 queue_send_info_to_clients(void)
722 g_idle_add(send_info_to_clients
, NULL
);
725 /******************************************************************************/
728 timeout_handler(gpointer data
)
730 send_info_to_clients(NULL
);
731 send_sats_to_clients(NULL
);
732 send_nmea_to_clients(NULL
);
734 return !!client_list
;
737 /******************************************************************************/
740 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE(
742 GValue
*return_value G_GNUC_UNUSED
,
743 guint n_param_values
,
744 const GValue
*param_values
,
745 gpointer invocation_hint G_GNUC_UNUSED
,
746 gpointer marshal_data
749 typedef void (*GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
)(
758 GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE callback
;
759 GCClosure
*cc
= (GCClosure
*) closure
;
760 gpointer data1
, data2
;
762 g_return_if_fail(n_param_values
== 6);
764 if (G_CCLOSURE_SWAP_DATA(closure
)) {
765 data1
= closure
->data
;
766 data2
= g_value_peek_pointer(param_values
+ 0);
768 data1
= g_value_peek_pointer(param_values
+ 0);
769 data2
= closure
->data
;
772 callback
= (GMarshalFunc_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
) (
773 marshal_data
? marshal_data
: cc
->callback
);
776 g_value_get_int(param_values
+ 1),
777 g_value_get_int(param_values
+ 2),
778 g_value_get_double(param_values
+ 3),
779 g_value_get_double(param_values
+ 4),
780 g_value_get_double(param_values
+ 5),
785 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE(
787 GValue
*return_value G_GNUC_UNUSED
,
788 guint n_param_values
,
789 const GValue
*param_values
,
790 gpointer invocation_hint G_GNUC_UNUSED
,
791 gpointer marshal_data
794 typedef void (*GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE
)(
802 GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE callback
;
803 GCClosure
*cc
= (GCClosure
*) closure
;
804 gpointer data1
, data2
;
806 g_return_if_fail(n_param_values
== 5);
808 if (G_CCLOSURE_SWAP_DATA(closure
)) {
809 data1
= closure
->data
;
810 data2
= g_value_peek_pointer(param_values
+ 0);
812 data1
= g_value_peek_pointer(param_values
+ 0);
813 data2
= closure
->data
;
816 callback
= (GMarshalFunc_VOID__INT_DOUBLE_DOUBLE_DOUBLE
) (
817 marshal_data
? marshal_data
: cc
->callback
);
820 g_value_get_int(param_values
+ 1),
821 g_value_get_double(param_values
+ 2),
822 g_value_get_double(param_values
+ 3),
823 g_value_get_double(param_values
+ 4),
827 /******************************************************************************/
830 connection_status_changed(
832 gboolean connectionstatus
,
836 device_connectionstatus
= connectionstatus
;
838 g_message("ConnectionStatusChanged(connectionstatus=%s)",
839 device_connectionstatus
? "TRUE" : "FALSE");
841 if ((client_list
|| nowait
) && !device_connectionstatus
) {
842 dbus_g_proxy_call_no_reply(proxy_usage
, "RequestResource",
843 G_TYPE_STRING
, "GPS",
858 device_fixstatus
= fixstatus
;
860 switch (device_fixstatus
) {
861 case 1: str
= "NONE"; break;
862 case 2: str
= "2D"; break;
863 case 3: str
= "3D"; break;
864 default: str
= "INVALID"; break;
867 g_message("FixStatusChanged(fixstatus=%s)", str
);
869 g_string_truncate(nmea_gga
, 0);
870 g_string_truncate(nmea_gsa
, 0);
871 g_string_truncate(nmea_rmc
, 0);
872 g_string_truncate(nmea_gll
, 0);
874 queue_send_nmea_to_clients();
875 queue_send_info_to_clients();
889 position_timestamp
= timestamp
;
890 position_latitude
= (fields
& (1 << 0)) ? latitude
: NAN
;
891 position_longitude
= (fields
& (1 << 1)) ? longitude
: NAN
;
892 position_altitude
= (fields
& (1 << 2)) ? altitude
: NAN
;
894 g_debug("PositionChanged(timestamp=%d, latitude=%f, longitude=%f, altitude=%f)",
895 position_timestamp
, position_latitude
,
896 position_longitude
, position_altitude
);
898 g_string_truncate(nmea_gga
, 0);
899 g_string_truncate(nmea_rmc
, 0);
900 g_string_truncate(nmea_gll
, 0);
902 queue_send_nmea_to_clients();
903 queue_send_info_to_clients();
916 accuracy_pdop
= (fields
& (1 << 0)) ? pdop
: NAN
;
917 accuracy_hdop
= (fields
& (1 << 1)) ? hdop
: NAN
;
918 accuracy_vdop
= (fields
& (1 << 2)) ? vdop
: NAN
;
920 g_debug("AccuracyChanged(pdop=%f, hdop=%f, vdop=%f)",
921 accuracy_pdop
, accuracy_hdop
, accuracy_vdop
);
923 g_string_truncate(nmea_gga
, 0);
924 g_string_truncate(nmea_gsa
, 0);
926 queue_send_nmea_to_clients();
927 queue_send_info_to_clients();
941 course_timestamp
= timestamp
;
942 course_speed
= (fields
& (1 << 0)) ? speed
: NAN
;
943 course_direction
= (fields
& (1 << 1)) ? direction
: NAN
;
944 course_climb
= (fields
& (1 << 2)) ? climb
: NAN
;
946 g_debug("CourseChanged(timestamp=%d, speed=%f, direction=%f, climb=%f)",
947 course_timestamp
, course_speed
,
948 course_direction
, course_climb
);
950 g_string_truncate(nmea_rmc
, 0);
951 g_string_truncate(nmea_vtg
, 0);
953 queue_send_nmea_to_clients();
954 queue_send_info_to_clients();
960 GPtrArray
*satellites
,
967 satellite_satellitec
= 0;
969 satellite_satellitec
= MIN(SATELLITEC_MAX
, satellites
->len
);
972 for (i
= 0; i
< satellite_satellitec
; i
++) {
973 struct satellite
*sat
;
976 sat
= satellite_satellitev
+ i
;
977 val
= satellites
->pdata
[i
];
979 sat
->prn
= g_value_get_uint(g_value_array_get_nth(val
, 0));
980 sat
->used
= g_value_get_boolean(g_value_array_get_nth(val
, 1));
981 sat
->elevation
= g_value_get_uint(g_value_array_get_nth(val
, 2));
982 sat
->azimuth
= g_value_get_uint(g_value_array_get_nth(val
, 3));
983 sat
->snr
= g_value_get_uint(g_value_array_get_nth(val
, 4));
985 g_debug("SatellitesChanged(index=%d, prn=%u, used=%s, elevation=%u, azimuth=%u, snr=%u)",
988 sat
->used
? "TRUE" : "FALSE",
994 g_string_truncate(nmea_gga
, 0);
995 g_string_truncate(nmea_gsa
, 0);
996 g_string_truncate(nmea_gsv
[0], 0);
997 g_string_truncate(nmea_gsv
[1], 0);
998 g_string_truncate(nmea_gsv
[2], 0);
1000 queue_send_nmea_to_clients();
1001 queue_send_sats_to_clients();
1011 time_seconds
= seconds
;
1013 g_debug("TimeChanged(seconds=%d)", time_seconds
);
1015 g_string_truncate(nmea_gga
, 0);
1016 g_string_truncate(nmea_rmc
, 0);
1017 g_string_truncate(nmea_gll
, 0);
1019 queue_send_nmea_to_clients();
1020 queue_send_info_to_clients();
1023 /******************************************************************************/
1028 dbus_g_proxy_connect_signal(proxy_device
, "ConnectionStatusChanged",
1029 G_CALLBACK(connection_status_changed
), NULL
, NULL
);
1030 dbus_g_proxy_connect_signal(proxy_device
, "FixStatusChanged",
1031 G_CALLBACK(fix_status_changed
), NULL
, NULL
);
1032 dbus_g_proxy_connect_signal(proxy_position
, "PositionChanged",
1033 G_CALLBACK(position_changed
), NULL
, NULL
);
1034 dbus_g_proxy_connect_signal(proxy_accuracy
, "AccuracyChanged",
1035 G_CALLBACK(accuracy_changed
), NULL
, NULL
);
1036 dbus_g_proxy_connect_signal(proxy_course
, "CourseChanged",
1037 G_CALLBACK(course_changed
), NULL
, NULL
);
1038 dbus_g_proxy_connect_signal(proxy_satellite
, "SatellitesChanged",
1039 G_CALLBACK(satellites_changed
), NULL
, NULL
);
1040 dbus_g_proxy_connect_signal(proxy_time
, "TimeChanged",
1041 G_CALLBACK(time_changed
), NULL
, NULL
);
1043 dbus_g_proxy_call_no_reply(proxy_usage
, "RequestResource",
1044 G_TYPE_STRING
, "GPS",
1049 gboolean connectionstatus
= FALSE
;
1051 dbus_g_proxy_call(proxy_device
, "GetConnectionStatus", NULL
,
1053 G_TYPE_BOOLEAN
, &connectionstatus
,
1055 connection_status_changed(NULL
, connectionstatus
, NULL
);
1060 dbus_g_proxy_call(proxy_device
, "GetFixStatus", NULL
,
1062 G_TYPE_INT
, &fixstatus
,
1064 fix_status_changed(NULL
, fixstatus
, NULL
);
1067 int fields
= 0, timestamp
= 0;
1068 double latitude
= NAN
, longitude
= NAN
, altitude
= NAN
;
1070 dbus_g_proxy_call(proxy_position
, "GetPosition", NULL
,
1072 G_TYPE_INT
, &fields
,
1073 G_TYPE_INT
, ×tamp
,
1074 G_TYPE_DOUBLE
, &latitude
,
1075 G_TYPE_DOUBLE
, &longitude
,
1076 G_TYPE_DOUBLE
, &altitude
,
1078 position_changed(NULL
, fields
, timestamp
, latitude
, longitude
,
1083 double pdop
= NAN
, hdop
= NAN
, vdop
= NAN
;
1085 dbus_g_proxy_call(proxy_accuracy
, "GetAccuracy", NULL
,
1087 G_TYPE_INT
, &fields
,
1088 G_TYPE_DOUBLE
, &pdop
,
1089 G_TYPE_DOUBLE
, &hdop
,
1090 G_TYPE_DOUBLE
, &vdop
,
1092 accuracy_changed(NULL
, fields
, pdop
, hdop
, vdop
, NULL
);
1095 int fields
= 0, timestamp
= 0;
1096 double speed
= NAN
, direction
= NAN
, climb
= NAN
;
1098 dbus_g_proxy_call(proxy_course
, "GetCourse", NULL
,
1100 G_TYPE_INT
, &fields
,
1101 G_TYPE_INT
, ×tamp
,
1102 G_TYPE_DOUBLE
, &speed
,
1103 G_TYPE_DOUBLE
, &direction
,
1104 G_TYPE_DOUBLE
, &climb
,
1106 course_changed(NULL
, fields
, timestamp
, speed
, direction
,
1110 GPtrArray
*satellites
= NULL
;
1112 dbus_g_proxy_call(proxy_satellite
, "GetSatellites", NULL
,
1114 dbus_g_type_get_collection("GPtrArray",
1115 dbus_g_type_get_struct("GValueArray",
1124 satellites_changed(NULL
, satellites
, NULL
);
1129 dbus_g_proxy_call(proxy_time
, "GetTime", NULL
,
1131 G_TYPE_INT
, &seconds
,
1133 time_changed(NULL
, seconds
, NULL
);
1140 dbus_g_proxy_call_no_reply(proxy_usage
, "ReleaseResource",
1141 G_TYPE_STRING
, "GPS",
1145 dbus_g_proxy_disconnect_signal(proxy_device
, "ConnectionStatusChanged",
1146 G_CALLBACK(connection_status_changed
), NULL
);
1147 dbus_g_proxy_disconnect_signal(proxy_device
, "FixStatusChanged",
1148 G_CALLBACK(fix_status_changed
), NULL
);
1149 dbus_g_proxy_disconnect_signal(proxy_position
, "PositionChanged",
1150 G_CALLBACK(position_changed
), NULL
);
1151 dbus_g_proxy_disconnect_signal(proxy_accuracy
, "AccuracyChanged",
1152 G_CALLBACK(accuracy_changed
), NULL
);
1153 dbus_g_proxy_disconnect_signal(proxy_course
, "CourseChanged",
1154 G_CALLBACK(course_changed
), NULL
);
1155 dbus_g_proxy_disconnect_signal(proxy_satellite
, "SatellitesChanged",
1156 G_CALLBACK(satellites_changed
), NULL
);
1157 dbus_g_proxy_disconnect_signal(proxy_time
, "TimeChanged",
1158 G_CALLBACK(time_changed
), NULL
);
1161 /******************************************************************************/
1166 GError
*error
= NULL
;
1168 connection
= dbus_g_bus_get(DBUS_BUS_SYSTEM
, &error
);
1171 g_printerr("Failed to open connection to system bus: %s\n",
1173 g_error_free(error
);
1177 dbus_g_object_register_marshaller(
1178 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE
,
1185 dbus_g_object_register_marshaller(
1186 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE
,
1195 proxy_usage
= dbus_g_proxy_new_for_name(connection
, OUSAGED
, USAGE
,
1196 "org.freesmartphone.Usage");
1197 proxy_device
= dbus_g_proxy_new_for_name(connection
, OGPSD
, GYPSY
,
1198 "org.freedesktop.Gypsy.Device");
1199 proxy_position
= dbus_g_proxy_new_for_name(connection
, OGPSD
, GYPSY
,
1200 "org.freedesktop.Gypsy.Position");
1201 proxy_accuracy
= dbus_g_proxy_new_for_name(connection
, OGPSD
, GYPSY
,
1202 "org.freedesktop.Gypsy.Accuracy");
1203 proxy_course
= dbus_g_proxy_new_for_name(connection
, OGPSD
, GYPSY
,
1204 "org.freedesktop.Gypsy.Course");
1205 proxy_satellite
= dbus_g_proxy_new_for_name(connection
, OGPSD
, GYPSY
,
1206 "org.freedesktop.Gypsy.Satellite");
1207 proxy_time
= dbus_g_proxy_new_for_name(connection
, OGPSD
, GYPSY
,
1208 "org.freedesktop.Gypsy.Time");
1210 dbus_g_proxy_add_signal(proxy_device
, "ConnectionStatusChanged",
1213 dbus_g_proxy_add_signal(proxy_device
, "FixStatusChanged",
1216 dbus_g_proxy_add_signal(proxy_position
, "PositionChanged",
1223 dbus_g_proxy_add_signal(proxy_accuracy
, "AccuracyChanged",
1229 dbus_g_proxy_add_signal(proxy_course
, "CourseChanged",
1236 dbus_g_proxy_add_signal(proxy_satellite
, "SatellitesChanged",
1237 dbus_g_type_get_collection("GPtrArray",
1238 dbus_g_type_get_struct("GValueArray",
1246 dbus_g_proxy_add_signal(proxy_time
, "TimeChanged",
1251 /******************************************************************************/
1254 read_from_client(GIOChannel
*source
, GIOCondition condition
, gpointer data
)
1256 struct client
*client
;
1258 gsize len
= sizeof(buf
);
1265 status
= g_io_channel_read_chars(source
, buf
, len
- 2, &len
, NULL
);
1267 if ((status
== G_IO_STATUS_ERROR
) || (status
== G_IO_STATUS_EOF
)) {
1268 remove_client(client
);
1272 if (buf
[len
- 1] != '\n') {
1279 g_message("Received command from client: %s", buf
); /* FIXME */
1281 reply
= g_string_sized_new(128);
1282 g_string_assign(reply
, "GPSD");
1287 switch (toupper(*p
++)) {
1289 if (isnan(position_altitude
)) {
1290 g_string_append(reply
, ",A=?");
1292 g_string_append_printf(reply
, ",A=%.3f",
1297 g_string_append(reply
, ",B=?");
1300 g_string_append(reply
, ",C=1.00"); /* FIXME */
1303 if (time_seconds
<= 0) {
1304 g_string_append(reply
, ",D=?");
1309 seconds
= time_seconds
;
1310 tm
= gmtime(&seconds
);
1312 g_string_append_printf(reply
,
1313 ",D=%04d-%02d-%02dT%02d:%02d:%02d.00Z",
1314 tm
->tm_year
+ 1900, tm
->tm_mon
+ 1,
1315 tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
,
1320 g_string_append(reply
, ",E=");
1322 if (isnan(accuracy_pdop
)) {
1323 g_string_append(reply
, "?");
1325 g_string_append_printf(reply
, "%.2f",
1328 if (isnan(accuracy_hdop
)) {
1329 g_string_append(reply
, " ?");
1331 g_string_append_printf(reply
, " %.2f",
1334 if (isnan(accuracy_vdop
)) {
1335 g_string_append(reply
, " ?");
1337 g_string_append_printf(reply
, " %.2f",
1343 while (isprint(*p
) && !isspace(*p
)) {
1347 g_string_append(reply
, ",F=gypsy");
1351 p
+= strcspn(p
, ",\r\n");
1353 g_string_append(reply
, ",G=GPS");
1356 g_string_append(reply
, ",I=gypsy");
1362 if (*p
== '1' || *p
== '+') {
1364 g_string_append(reply
, ",J=1");
1366 if (*p
== '0' || *p
== '-') {
1369 g_string_append(reply
, ",J=0");
1373 g_string_append(reply
, ",K=1 gypsy");
1376 g_string_append(reply
, ",L=3 " VERSION
1377 " abcdefgijklmnopqrstuvwxyz");
1380 g_string_append_printf(reply
, ",M=%d",
1384 g_string_append(reply
, ",N=0");
1390 if (isnan(position_latitude
)
1391 || isnan(position_longitude
)) {
1392 g_string_append(reply
, ",P=?");
1394 g_string_append_printf(reply
, ",P=%.6f %.6f",
1395 position_latitude
, position_longitude
);
1399 if (isnan(accuracy_pdop
)
1400 && isnan(accuracy_hdop
)
1401 && isnan(accuracy_vdop
)) {
1402 g_string_append(reply
, ",Q=?");
1406 for (i
= 0, used
= 0; i
< satellite_satellitec
; i
++) {
1407 if (satellite_satellitev
[i
].used
) {
1412 g_string_append_printf(reply
,
1413 ",Q=%d %.2f %.2f %.2f %.2f %.2f", used
,
1414 isnan(accuracy_pdop
) ? 0.0 : accuracy_pdop
,
1415 isnan(accuracy_hdop
) ? 0.0 : accuracy_hdop
,
1416 isnan(accuracy_vdop
) ? 0.0 : accuracy_vdop
,
1424 if (*p
== '2' || *p
== '1' || *p
== '+') {
1427 } else if (*p
== '0' || *p
== '-') {
1428 client
->raw
= FALSE
;
1431 client
->raw
= !client
->raw
;
1433 g_string_append_printf(reply
, ",R=%1d", client
->raw
);
1436 g_string_append_printf(reply
, ",S=%d",
1437 MAX(get_fixstatus() - 1, 0));
1440 if (isnan(course_direction
)) {
1441 g_string_append(reply
, ",T=?");
1443 g_string_append_printf(reply
, ",T=%.4f",
1448 if (isnan(course_climb
)) {
1449 g_string_append(reply
, ",U=?");
1451 g_string_append_printf(reply
, ",U=%.3f",
1456 if (isnan(course_speed
)) {
1457 g_string_append(reply
, ",V=?");
1459 g_string_append_printf(reply
, ",V=%.3f",
1460 course_speed
/ (KNOTS
* 2));
1467 if (*p
== '1' || *p
== '+') {
1468 client
->watcher
= TRUE
;
1470 } else if (*p
== '0' || *p
== '-') {
1471 client
->watcher
= FALSE
;
1474 client
->watcher
= !client
->watcher
;
1476 g_string_append_printf(reply
, ",W=%1d", client
->watcher
);
1479 if (time_seconds
<= 0) {
1480 g_string_append(reply
, ",X=?");
1482 g_string_append_printf(reply
, ",X=%d.000000",
1490 g_string_append(reply
, ",Z=?"); /* FIXME */
1493 g_string_append(reply
, ",$=?"); /* FIXME */
1504 g_string_append(reply
, "\r\n");
1505 send_to_client(client
, reply
->str
, reply
->len
);
1506 g_string_free(reply
, TRUE
);
1511 accept_new_client(GIOChannel
*source
, GIOCondition condition
, gpointer data
)
1513 struct sockaddr_in sin
;
1514 socklen_t len
= sizeof(sin
);
1515 struct client
*client
;
1518 g_message("New client request");
1520 fd
= accept(g_io_channel_unix_get_fd(source
),
1521 (struct sockaddr
*) &sin
, &len
);
1524 g_error("Cannot accept new connection: %s", strerror(errno
));
1527 client
= g_new0(struct client
, 1);
1530 g_error("Cannot allocate memory");
1534 g_timeout_add_seconds(1, timeout_handler
, NULL
);
1537 if (!client_list
&& !nowait
) {
1541 client_list
= g_list_prepend(client_list
, client
);
1543 client
->channel
= g_io_channel_unix_new(fd
);
1545 g_io_channel_set_flags(client
->channel
, G_IO_FLAG_NONBLOCK
, NULL
);
1546 g_io_channel_set_encoding(client
->channel
, NULL
, NULL
);
1547 g_io_channel_set_buffered(client
->channel
, FALSE
);
1549 g_io_add_watch(client
->channel
,
1550 G_IO_IN
| G_IO_PRI
| G_IO_HUP
| G_IO_ERR
,
1551 read_from_client
, client
);
1557 init_service(const char *service
)
1559 struct servent
*pse
;
1560 struct sockaddr_in sin
;
1561 GIOChannel
*channel
;
1564 memset(&sin
, 0, sizeof(sin
));
1566 sin
.sin_family
= AF_INET
;
1567 sin
.sin_addr
.s_addr
= INADDR_ANY
;
1570 service
= getservbyname("gpsd", "tcp") ? "gpsd" : PORT
;
1573 pse
= getservbyname(service
, "tcp");
1576 sin
.sin_port
= pse
->s_port
;
1578 sin
.sin_port
= htons(atoi(service
));
1581 if (!sin
.sin_port
) {
1582 g_error("Cannot get service entry: %s", service
);
1585 fd
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
1588 g_error("Cannot create socket: %s", strerror(errno
));
1591 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) & one
, sizeof(one
));
1593 if (bind(fd
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
1594 g_error("Cannot bind to port %s: %s", service
, strerror(errno
));
1597 if (listen(fd
, 4) < 0) {
1598 g_error("Cannot listen on port %s: %s",
1599 service
, strerror(errno
));
1602 channel
= g_io_channel_unix_new(fd
);
1604 g_io_channel_set_encoding(channel
, NULL
, NULL
);
1605 g_io_channel_set_buffered(channel
, FALSE
);
1607 g_io_add_watch(channel
, G_IO_IN
| G_IO_PRI
| G_IO_HUP
| G_IO_ERR
,
1608 accept_new_client
, NULL
);
1611 /******************************************************************************/
1614 print_to_syslog(const char *string
)
1616 syslog(LOG_USER
| LOG_INFO
, "%s", string
);
1622 GLogLevelFlags level
,
1623 const char *message
,
1627 const char *prefix
= NULL
;
1630 if ((level
& G_LOG_LEVEL_MASK
) == G_LOG_LEVEL_DEBUG
) {
1634 switch (level
& G_LOG_LEVEL_MASK
) {
1635 case G_LOG_LEVEL_ERROR
: prefix
= "ERROR: "; break;
1636 case G_LOG_LEVEL_CRITICAL
: prefix
= "CRITICAL: "; break;
1637 case G_LOG_LEVEL_WARNING
: prefix
= "WARNING: "; break;
1638 case G_LOG_LEVEL_MESSAGE
: prefix
= "MESSAGE: "; break;
1639 case G_LOG_LEVEL_INFO
: prefix
= "INFO: "; break;
1640 case G_LOG_LEVEL_DEBUG
: prefix
= "DEBUG: "; break;
1644 string
= g_string_new(prefix
);
1647 g_string_append_printf(string
, "%s: ", domain
);
1650 g_string_append(string
, message
);
1652 print_to_syslog(string
->str
);
1654 g_string_free(string
, TRUE
);
1657 /******************************************************************************/
1662 printf("usage: "NAME
" [-n] [-N] [-P pidfile] [-S port] [-h]\n\
1664 -n = don't wait for client connects to poll GPS\n\
1665 -N = don't go into background\n\
1666 -P pidfile = set file to record process ID\n\
1667 -S integer (default "PORT
") = set port for daemon\n\
1668 -h = help message\n\
1669 -V = emit version and exit.\n");
1672 /******************************************************************************/
1675 main(int argc
, char **argv
)
1677 GMainLoop
*loop
= NULL
;
1678 gboolean background
= TRUE
;
1679 char *service
= NULL
;
1680 char *pid_file
= NULL
;
1682 g_set_prgname(NAME
);
1688 option
= getopt(argc
, argv
, "F:D:S:bhNnP:VR:");
1696 g_warning("Not implemented: -D");
1699 g_warning("Not implemented: -F");
1705 g_warning("Not implemented: -b");
1708 g_warning("Not implemented: -R");
1720 printf(NAME
" "VERSION
"\n");
1739 g_error("fork() failed");
1740 } else if (pid
> 0) {
1744 openlog(NAME
, LOG_PID
, LOG_USER
);
1745 g_set_printerr_handler(print_to_syslog
);
1746 g_log_set_default_handler(log_to_syslog
, NULL
);
1749 g_error("setsid() failed");
1754 fd
= open("/dev/null", O_RDWR
, 0);
1757 g_error("Cannot open /dev/null");
1760 dup2(fd
, STDIN_FILENO
);
1761 dup2(fd
, STDOUT_FILENO
);
1762 dup2(fd
, STDERR_FILENO
);
1770 fp
= fopen(pid_file
, "w");
1773 g_error("Cannot create PID file: %s", pid_file
);
1776 fprintf(fp
, "%u\n", (unsigned) getpid());
1782 loop
= g_main_loop_new(NULL
, FALSE
);
1784 nmea_gga
= g_string_new(NULL
);
1785 nmea_gsa
= g_string_new(NULL
);
1786 nmea_gsv
[0] = g_string_new(NULL
);
1787 nmea_gsv
[1] = g_string_new(NULL
);
1788 nmea_gsv
[2] = g_string_new(NULL
);
1789 nmea_rmc
= g_string_new(NULL
);
1790 nmea_gll
= g_string_new(NULL
);
1791 nmea_vtg
= g_string_new(NULL
);
1793 init_service(service
);
1801 g_main_loop_run(loop
);