Improved Gypsy compatibility
[fso-gpsd.git] / fso-gpsd.c
blobae4278d67d8d48168c3ab6c33b6200aaf1e565e0
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.
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <syslog.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <netdb.h>
28 #include <math.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <dbus/dbus-glib.h>
34 #include <glib-object.h>
35 #include <glib.h>
37 #define KNOTS_TO_KPH (1.852)
38 #define KNOTS_TO_MPS (0.51444444)
40 /******************************************************************************/
42 #define ERROR(...) \
43 do { \
44 g_log(NULL, G_LOG_LEVEL_ERROR, __VA_ARGS__); \
45 abort(); \
46 } while (0)
48 #define CRITICAL(...) \
49 do { \
50 if (log_level & G_LOG_LEVEL_CRITICAL) { \
51 g_log(NULL, G_LOG_LEVEL_CRITICAL, __VA_ARGS__); \
52 } \
53 } while (0)
55 #define WARNING(...) \
56 do { \
57 if (log_level & G_LOG_LEVEL_WARNING) { \
58 g_log(NULL, G_LOG_LEVEL_WARNING, __VA_ARGS__); \
59 } \
60 } while (0)
62 #define MESSAGE(...) \
63 do { \
64 if (log_level & G_LOG_LEVEL_MESSAGE) { \
65 g_log(NULL, G_LOG_LEVEL_MESSAGE, __VA_ARGS__); \
66 } \
67 } while (0)
69 #define INFO(...) \
70 do { \
71 if (log_level & G_LOG_LEVEL_INFO) { \
72 g_log(NULL, G_LOG_LEVEL_INFO, __VA_ARGS__); \
73 } \
74 } while (0)
76 #define DEBUG(...) \
77 do { \
78 if (log_level & G_LOG_LEVEL_DEBUG) { \
79 g_log(NULL, G_LOG_LEVEL_DEBUG, __VA_ARGS__); \
80 } \
81 } while (0)
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 /******************************************************************************/
99 struct client {
100 GIOChannel *channel;
101 gboolean watcher;
102 gboolean raw;
105 struct satellite {
106 unsigned prn;
107 gboolean used;
108 unsigned elevation;
109 unsigned azimuth;
110 unsigned snr;
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 /******************************************************************************/
204 static int
205 get_fixstatus(void)
207 if (POSITION_LATITUDE_IS_VALID && POSITION_LONGITUDE_IS_VALID) {
208 if (POSITION_ALTITUDE_IS_VALID) {
209 return MIN(device_fixstatus, 3);
210 } else {
211 return MIN(device_fixstatus, 2);
213 } else {
214 return MIN(device_fixstatus, 1);
218 static gboolean
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);
228 } else {
229 return (tv1_sec > tv2_sec);
233 /******************************************************************************/
235 static void
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;
246 client->raw = FALSE;
249 static void
250 send_to_client(struct client *client, const char *string, gsize len)
252 GIOStatus status;
253 gsize bytes_written;
255 if (!client->channel) {
256 return;
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 /******************************************************************************/
269 static void
270 add_nmea_checksum(GString *nmea)
272 int checksum = 0;
273 char *p;
275 p = nmea->str;
277 if (*p == '$') {
278 p++;
281 while (*p) {
282 checksum ^= (int) *p;
283 p++;
286 g_string_append_printf(nmea, "*%02x", checksum);
289 static void
290 add_nmea_time(GString *nmea)
292 if (time_seconds <= 0) {
293 g_string_append_c(nmea, ',');
294 } else {
295 struct tm *tm;
296 time_t seconds;
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);
306 static void
307 add_nmea_latitude(GString *nmea)
309 if (!POSITION_LATITUDE_IS_VALID) {
310 g_string_append_c(nmea, ',');
311 g_string_append_c(nmea, ',');
312 } else {
313 double a, d;
315 a = fabs(position_latitude);
316 d = floor(a);
318 g_string_append_printf(nmea, ",%010.5f,%c",
319 (d * 100.0) + ((a - d) * 60.0),
320 (position_latitude > 0) ? 'N' : 'S');
324 static void
325 add_nmea_longitude(GString *nmea)
327 if (!POSITION_LONGITUDE_IS_VALID) {
328 g_string_append_c(nmea, ',');
329 g_string_append_c(nmea, ',');
330 } else {
331 double a, d;
333 a = fabs(position_longitude);
334 d = floor(a);
336 g_string_append_printf(nmea, ",%011.5f,%c",
337 (d * 100.0) + ((a - d) * 60.0),
338 (position_longitude > 0) ? 'E' : 'W');
342 /******************************************************************************/
344 static void
345 update_nmea_gga(void)
347 unsigned i, used;
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) {
361 used++;
365 g_string_append_printf(nmea_gga, ",%02d", used);
367 if (!ACCURACY_HDOP_IS_VALID) {
368 g_string_append_c(nmea_gga, ',');
369 } else {
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, ',');
376 } else {
377 g_string_append_printf(nmea_gga, ",%03.1f,M",
378 position_altitude);
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);
389 static void
390 update_nmea_gsa(void)
392 unsigned i;
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);
405 } else {
406 g_string_append_c(nmea_gsa, ',');
410 if (!ACCURACY_PDOP_IS_VALID) {
411 g_string_append_c(nmea_gsa, ',');
412 } else {
413 g_string_append_printf(nmea_gsa, ",%04.2f", accuracy_pdop);
416 if (!ACCURACY_HDOP_IS_VALID) {
417 g_string_append_c(nmea_gsa, ',');
418 } else {
419 g_string_append_printf(nmea_gsa, ",%04.2f", accuracy_hdop);
422 if (!ACCURACY_VDOP_IS_VALID) {
423 g_string_append_c(nmea_gsa, ',');
424 } else {
425 g_string_append_printf(nmea_gsa, ",%04.2f", accuracy_vdop);
428 add_nmea_checksum(nmea_gsa);
431 static void
432 update_nmea_gsv(void)
434 unsigned i;
435 unsigned sat_count;
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");
444 return;
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;
453 index_div = i / 4;
454 index_mod = i % 4;
456 if (index_mod == 0) {
457 g_string_append_printf(nmea_gsv[index_div],
458 "$GPGSV,%1d,%1d,%02d",
459 sentence_count,
460 index_div + 1,
461 sat_count);
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]);
479 static void
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');
489 } else {
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, ',');
500 } else {
501 g_string_append_printf(nmea_rmc, ",%07.3f",
502 course_speed);
505 if (!COURSE_DIRECTION_IS_VALID) {
506 g_string_append_c(nmea_rmc, ',');
507 } else {
508 g_string_append_printf(nmea_rmc, ",%06.2f",
509 course_direction);
512 if (time_seconds <= 0) {
513 g_string_append_c(nmea_rmc, ',');
514 } else {
515 struct tm *tm;
516 time_t seconds;
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);
531 static void
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');
545 } else {
546 g_string_append_c(nmea_gll, ',');
547 g_string_append_c(nmea_gll, 'V');
550 add_nmea_checksum(nmea_gll);
553 static void
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, ',');
561 } else {
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, ',');
573 } else {
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 /******************************************************************************/
583 static gboolean
584 send_nmea_to_clients(gpointer data)
586 GString *string;
587 GList *l;
589 for (string = NULL, l = client_list; l; l = l->next) {
590 struct client *client = l->data;
592 if (client->raw) {
593 if (!string) {
594 static GTimeVal timestamp = { 0, 0 };
596 if (data && check_period(&timestamp, data, 1)) {
597 return FALSE;
600 g_get_current_time(&timestamp);
602 string = g_string_sized_new(1024);
604 if (!nmea_gga->len) {
605 update_nmea_gga();
607 if (!nmea_gsa->len) {
608 update_nmea_gsa();
610 if (!nmea_gsv[0]->len) {
611 update_nmea_gsv();
613 if (!nmea_rmc->len) {
614 update_nmea_rmc();
616 if (!nmea_gll->len) {
617 update_nmea_gll();
619 if (!nmea_vtg->len) {
620 update_nmea_vtg();
623 if (nmea_gga->len) {
624 INFO("Sending nmea: %s",
625 nmea_gga->str);
626 g_string_append_len(string,
627 nmea_gga->str,
628 nmea_gga->len);
629 g_string_append_c(string, '\r');
630 g_string_append_c(string, '\n');
632 if (nmea_gsa->len) {
633 INFO("Sending nmea: %s",
634 nmea_gsa->str);
635 g_string_append_len(string,
636 nmea_gsa->str,
637 nmea_gsa->len);
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",
643 nmea_gsv[0]->str);
644 g_string_append_len(string,
645 nmea_gsv[0]->str,
646 nmea_gsv[0]->len);
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",
652 nmea_gsv[1]->str);
653 g_string_append_len(string,
654 nmea_gsv[1]->str,
655 nmea_gsv[1]->len);
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",
661 nmea_gsv[2]->str);
662 g_string_append_len(string,
663 nmea_gsv[2]->str,
664 nmea_gsv[2]->len);
665 g_string_append_c(string, '\r');
666 g_string_append_c(string, '\n');
668 if (nmea_rmc->len) {
669 INFO("Sending nmea: %s",
670 nmea_rmc->str);
671 g_string_append_len(string,
672 nmea_rmc->str,
673 nmea_rmc->len);
674 g_string_append_c(string, '\r');
675 g_string_append_c(string, '\n');
677 if (nmea_gll->len) {
678 INFO("Sending nmea: %s",
679 nmea_gll->str);
680 g_string_append_len(string,
681 nmea_gll->str,
682 nmea_gll->len);
683 g_string_append_c(string, '\r');
684 g_string_append_c(string, '\n');
686 if (nmea_vtg->len) {
687 INFO("Sending nmea: %s",
688 nmea_vtg->str);
689 g_string_append_len(string,
690 nmea_vtg->str,
691 nmea_vtg->len);
692 g_string_append_c(string, '\r');
693 g_string_append_c(string, '\n');
697 send_to_client(client, string->str, string->len);
701 if (string) {
702 g_string_free(string, TRUE);
705 nmea_queued = FALSE;
707 return FALSE;
710 static void
711 queue_send_nmea_to_clients(void)
713 if (nmea_queued) {
714 return;
717 nmea_queued = TRUE;
719 g_idle_add(send_nmea_to_clients, NULL);
722 /******************************************************************************/
724 static void
725 add_sats(GString *string)
727 unsigned i, count;
729 if (satellite_satellitec == 0) {
730 g_string_append(string, ",Y=?");
731 return;
734 g_string_append(string, ",Y=-");
736 if (time_seconds <= 0) {
737 g_string_append(string, " ? ");
738 } else {
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 /******************************************************************************/
758 static gboolean
759 send_sats_to_clients(gpointer data)
761 GString *string;
762 GList *l;
764 for (string = NULL, l = client_list; l; l = l->next) {
765 struct client *client = l->data;
767 if (client->watcher) {
768 if (!string) {
769 static GTimeVal timestamp = { 0, 0 };
771 if (data && check_period(&timestamp, data, 1)) {
772 return FALSE;
775 g_get_current_time(&timestamp);
777 string = g_string_sized_new(1024);
779 g_string_append(string, "GPSD");
781 add_sats(string);
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);
793 if (string) {
794 g_string_free(string, TRUE);
797 sats_queued = FALSE;
799 return FALSE;
802 static void
803 queue_send_sats_to_clients(void)
805 if (sats_queued) {
806 return;
809 sats_queued = TRUE;
811 g_idle_add(send_sats_to_clients, NULL);
814 /******************************************************************************/
816 static void
817 add_info(GString *string)
819 if (!device_connectionstatus || get_fixstatus() <= 1) {
820 g_string_append(string, ",O=?");
821 return;
824 g_string_append(string, ",O=-");
826 if (time_seconds <= 0) {
827 g_string_append_c(string, ' ');
828 g_string_append_c(string, '?');
829 } else {
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, '?');
839 } else {
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, '?');
845 } else {
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, '?');
851 } else {
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, '?');
857 } else {
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, '?');
863 } else {
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, '?');
869 } else {
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, '?');
875 } else {
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, '?');
882 } else {
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 /******************************************************************************/
893 static gboolean
894 send_info_to_clients(gpointer data)
896 GString *string;
897 GList *l;
899 for (string = NULL, l = client_list; l; l = l->next) {
900 struct client *client = l->data;
902 if (client->watcher) {
903 if (!string) {
904 static GTimeVal timestamp = { 0, 0 };
906 if (data && check_period(&timestamp, data, 1)) {
907 return FALSE;
910 g_get_current_time(&timestamp);
912 string = g_string_sized_new(1024);
914 g_string_append(string, "GPSD");
916 add_info(string);
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);
928 if (string) {
929 g_string_free(string, TRUE);
932 info_queued = FALSE;
934 return FALSE;
937 static void
938 queue_send_info_to_clients(void)
940 if (info_queued) {
941 return;
944 info_queued = TRUE;
946 g_idle_add(send_info_to_clients, NULL);
949 /******************************************************************************/
951 static void
952 connection_status_changed(
953 DBusGProxy *proxy,
954 gboolean connectionstatus,
955 gpointer user_data
958 device_connectionstatus = connectionstatus;
960 INFO(GYPSY_DEVICE": ConnectionStatusChanged(connectionstatus=%s)",
961 device_connectionstatus ? "TRUE" : "FALSE");
964 static void
965 fix_status_changed(
966 DBusGProxy *proxy,
967 int fixstatus,
968 gpointer user_data
971 const char *str;
973 device_fixstatus = fixstatus;
975 switch (device_fixstatus) {
976 case 1:
977 str = "NONE";
978 break;
979 case 2:
980 str = "2D";
981 break;
982 case 3:
983 str = "3D";
984 break;
985 default:
986 str = "INVALID";
987 break;
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();
1001 static void
1002 time_changed(
1003 DBusGProxy *proxy,
1004 int seconds,
1005 gpointer user_data
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();
1020 static void
1021 position_changed(
1022 DBusGProxy *proxy,
1023 int fields,
1024 int timestamp,
1025 double latitude,
1026 double longitude,
1027 double altitude,
1028 gpointer user_data
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)",
1038 position_timestamp,
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();
1051 static void
1052 accuracy_changed(
1053 DBusGProxy *proxy,
1054 int fields,
1055 double pdop,
1056 double hdop,
1057 double vdop,
1058 gpointer user_data
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();
1078 static void
1079 course_changed(
1080 DBusGProxy *proxy,
1081 int fields,
1082 int timestamp,
1083 double speed,
1084 double direction,
1085 double climb,
1086 gpointer user_data
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)",
1096 course_timestamp,
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();
1108 static void
1109 satellites_changed(
1110 DBusGProxy *proxy,
1111 GPtrArray *satellites,
1112 gpointer user_data
1115 int i;
1117 if (!satellites) {
1118 satellite_satellitec = 0;
1119 } else {
1120 satellite_satellitec = MIN(SATELLITEC_MAX, satellites->len);
1123 for (i = 0; i < satellite_satellitec; i++) {
1124 struct satellite *sat;
1125 GValueArray *val;
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)",
1138 sat->prn,
1139 sat->used ? "TRUE" : "FALSE",
1140 sat->elevation,
1141 sat->azimuth,
1142 sat->snr);
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 /******************************************************************************/
1157 static void
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,
1167 G_TYPE_INVALID);
1169 if (error) {
1170 WARNING(GYPSY_DEVICE": GetConnectionStatus: %s", error->message);
1171 g_error_free(error);
1172 } else {
1173 DEBUG(GYPSY_DEVICE": GetConnectionStatus: OK");
1174 connection_status_changed(NULL, connectionstatus, NULL);
1178 static void
1179 get_fix_status_notify(DBusGProxy *proxy, DBusGProxyCall *call, gpointer data)
1181 GError *error = NULL;
1182 int fixstatus = 0;
1184 DEBUG(GYPSY_DEVICE": GetFixStatus: Notify");
1186 dbus_g_proxy_end_call(proxy, call, &error,
1187 G_TYPE_INT, &fixstatus,
1188 G_TYPE_INVALID);
1190 if (error) {
1191 WARNING(GYPSY_DEVICE": GetFixStatus: %s", error->message);
1192 g_error_free(error);
1193 } else {
1194 DEBUG(GYPSY_DEVICE": GetFixStatus: OK");
1195 fix_status_changed(NULL, fixstatus, NULL);
1199 static void
1200 get_time_notify(DBusGProxy *proxy, DBusGProxyCall *call, gpointer data)
1202 GError *error = NULL;
1203 int seconds = 0;
1205 DEBUG(GYPSY_TIME": GetTime: Notify");
1207 dbus_g_proxy_end_call(proxy, call, &error,
1208 G_TYPE_INT, &seconds,
1209 G_TYPE_INVALID);
1211 if (error) {
1212 WARNING(GYPSY_TIME": GetTime: %s", error->message);
1213 g_error_free(error);
1214 } else {
1215 DEBUG(GYPSY_TIME": GetTime: OK");
1216 time_changed(NULL, seconds, NULL);
1220 static void
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, &timestamp,
1232 G_TYPE_DOUBLE, &latitude,
1233 G_TYPE_DOUBLE, &longitude,
1234 G_TYPE_DOUBLE, &altitude,
1235 G_TYPE_INVALID);
1237 if (error) {
1238 WARNING(GYPSY_POSITION": GetPosition: %s", error->message);
1239 g_error_free(error);
1240 } else {
1241 DEBUG(GYPSY_POSITION": GetPosition: OK");
1242 position_changed(NULL, fields, timestamp, latitude, longitude,
1243 altitude, NULL);
1247 static void
1248 get_accuracy_notify(DBusGProxy *proxy, DBusGProxyCall *call, gpointer data)
1250 GError *error = NULL;
1251 int fields = 0;
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,
1261 G_TYPE_INVALID);
1263 if (error) {
1264 WARNING(GYPSY_ACCURACY": GetAccuracy: %s", error->message);
1265 g_error_free(error);
1266 } else {
1267 DEBUG(GYPSY_ACCURACY": GetAccuracy: OK");
1268 accuracy_changed(NULL, fields, pdop, hdop, vdop, NULL);
1272 static void
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, &timestamp,
1284 G_TYPE_DOUBLE, &speed,
1285 G_TYPE_DOUBLE, &direction,
1286 G_TYPE_DOUBLE, &climb,
1287 G_TYPE_INVALID);
1289 if (error) {
1290 WARNING(GYPSY_COURSE": GetCourse: %s", error->message);
1291 g_error_free(error);
1292 } else {
1293 DEBUG(GYPSY_COURSE": GetCourse: OK");
1294 course_changed(NULL, fields, timestamp, speed, direction,
1295 climb, NULL);
1299 static void
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",
1310 G_TYPE_UINT,
1311 G_TYPE_BOOLEAN,
1312 G_TYPE_UINT,
1313 G_TYPE_UINT,
1314 G_TYPE_UINT,
1315 G_TYPE_INVALID)),
1316 &satellites,
1317 G_TYPE_INVALID);
1319 if (error) {
1320 WARNING(GYPSY_SATELLITE": GetSatellites: %s", error->message);
1321 g_error_free(error);
1322 } else {
1323 DEBUG(GYPSY_SATELLITE": GetSatellites: OK");
1324 satellites_changed(NULL, satellites, NULL);
1328 /******************************************************************************/
1330 static void
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);
1339 if (error) {
1340 WARNING(GYPSY_DEVICE": Start: %s", error->message);
1341 g_error_free(error);
1342 gypsy_device_start_failed = TRUE;
1343 } else {
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,
1350 G_TYPE_INVALID);
1352 DEBUG(GYPSY_DEVICE": GetFixStatus");
1353 dbus_g_proxy_begin_call(device_proxy, "GetFixStatus",
1354 get_fix_status_notify, NULL, NULL,
1355 G_TYPE_INVALID);
1357 DEBUG(GYPSY_TIME": GetTime");
1358 dbus_g_proxy_begin_call(time_proxy, "GetTime",
1359 get_time_notify, NULL, NULL,
1360 G_TYPE_INVALID);
1362 DEBUG(GYPSY_POSITION": GetPosition");
1363 dbus_g_proxy_begin_call(position_proxy, "GetPosition",
1364 get_position_notify, NULL, NULL,
1365 G_TYPE_INVALID);
1367 DEBUG(GYPSY_ACCURACY": GetAccuracy");
1368 dbus_g_proxy_begin_call(accuracy_proxy, "GetAccuracy",
1369 get_accuracy_notify, NULL, NULL,
1370 G_TYPE_INVALID);
1372 DEBUG(GYPSY_COURSE": GetCourse");
1373 dbus_g_proxy_begin_call(course_proxy, "GetCourse",
1374 get_course_notify, NULL, NULL,
1375 G_TYPE_INVALID);
1377 DEBUG(GYPSY_SATELLITE": GetSatellites");
1378 dbus_g_proxy_begin_call(satellite_proxy, "GetSatellites",
1379 get_satellites_notify, NULL, NULL,
1380 G_TYPE_INVALID);
1384 /******************************************************************************/
1386 static void
1387 device_start(void)
1389 if (!gypsy_device_path) {
1390 WARNING("No device, not starting");
1391 return;
1394 gypsy_device_start_failed = FALSE;
1396 /* Device */
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,
1403 G_TYPE_INVALID);
1405 dbus_g_proxy_add_signal(device_proxy, "ConnectionStatusChanged",
1406 G_TYPE_BOOLEAN,
1407 G_TYPE_INVALID);
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",
1412 G_TYPE_INT,
1413 G_TYPE_INVALID);
1414 dbus_g_proxy_connect_signal(device_proxy, "FixStatusChanged",
1415 G_CALLBACK(fix_status_changed), NULL, NULL);
1417 /* Time */
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",
1422 G_TYPE_INT,
1423 G_TYPE_INVALID);
1424 dbus_g_proxy_connect_signal(time_proxy, "TimeChanged",
1425 G_CALLBACK(time_changed), NULL, NULL);
1427 /* Position */
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",
1432 G_TYPE_INT,
1433 G_TYPE_INT,
1434 G_TYPE_DOUBLE,
1435 G_TYPE_DOUBLE,
1436 G_TYPE_DOUBLE,
1437 G_TYPE_INVALID);
1438 dbus_g_proxy_connect_signal(position_proxy, "PositionChanged",
1439 G_CALLBACK(position_changed), NULL, NULL);
1441 /* Accuracy */
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",
1446 G_TYPE_INT,
1447 G_TYPE_DOUBLE,
1448 G_TYPE_DOUBLE,
1449 G_TYPE_DOUBLE,
1450 G_TYPE_INVALID);
1451 dbus_g_proxy_connect_signal(accuracy_proxy, "AccuracyChanged",
1452 G_CALLBACK(accuracy_changed), NULL, NULL);
1454 /* Course */
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",
1459 G_TYPE_INT,
1460 G_TYPE_INT,
1461 G_TYPE_DOUBLE,
1462 G_TYPE_DOUBLE,
1463 G_TYPE_DOUBLE,
1464 G_TYPE_INVALID);
1465 dbus_g_proxy_connect_signal(course_proxy, "CourseChanged",
1466 G_CALLBACK(course_changed), NULL, NULL);
1468 /* Satellites */
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",
1475 G_TYPE_UINT,
1476 G_TYPE_BOOLEAN,
1477 G_TYPE_UINT,
1478 G_TYPE_UINT,
1479 G_TYPE_UINT,
1480 G_TYPE_INVALID)),
1481 G_TYPE_INVALID);
1482 dbus_g_proxy_connect_signal(satellite_proxy, "SatellitesChanged",
1483 G_CALLBACK(satellites_changed), NULL, NULL);
1486 /******************************************************************************/
1488 static void
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);
1497 if (error) {
1498 WARNING(GYPSY_DEVICE": Stop: %s", error->message);
1499 g_error_free(error);
1500 } else {
1501 DEBUG(GYPSY_DEVICE": Stop: OK");
1505 static void
1506 device_stop(void)
1508 if (!gypsy_device_path) {
1509 WARNING("No device, not stopping");
1510 return;
1513 /* Device */
1514 if (gypsy_device_start_failed) {
1515 gypsy_device_start_failed = FALSE;
1516 } else {
1517 DEBUG(GYPSY_DEVICE": Stop");
1518 dbus_g_proxy_begin_call(device_proxy, "Stop",
1519 device_stop_notify, NULL, NULL,
1520 G_TYPE_INVALID);
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;
1532 /* Time */
1533 dbus_g_proxy_disconnect_signal(time_proxy, "TimeChanged",
1534 G_CALLBACK(time_changed), NULL);
1535 g_object_unref(G_OBJECT(time_proxy));
1536 time_proxy = NULL;
1537 time_seconds = 0;
1539 /* Position */
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;
1550 /* Accuracy */
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;
1560 /* Course */
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;
1565 course_fields = 0;
1566 course_timestamp = 0;
1567 course_speed = 0.0;
1568 course_direction = 0.0;
1569 course_climb = 0.0;
1571 /* Satellite */
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 /******************************************************************************/
1581 static void
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,
1591 G_TYPE_INVALID);
1593 if (error) {
1594 WARNING(GYPSY_SERVER": Create: %s", error->message);
1595 g_error_free(error);
1596 gypsy_device_create_failed = TRUE;
1597 gypsy_device_path = NULL;
1598 } else {
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) {
1604 device_start();
1609 static void
1610 server_create(void)
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,
1618 G_TYPE_INVALID);
1621 /******************************************************************************/
1623 static void
1624 name_owner_changed(
1625 DBusGProxy *proxy,
1626 const char *name,
1627 const char *prev,
1628 const char *new,
1629 gpointer user_data
1632 INFO("org.freedesktop.DBus: NameOwnerChanged(name=%s, prev=%s, new=%s)",
1633 name, prev, new);
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) {
1640 server_create();
1642 gypsy_device_path = NULL;
1646 /******************************************************************************/
1648 static gboolean
1649 timeout_handler(gpointer data)
1651 if (!client_list && !nowait) {
1652 DEBUG("Timeout: no client: removing timeout handler");
1653 timeout_handler_registered = FALSE;
1654 return FALSE;
1655 } else {
1656 if (gypsy_device_create_failed) {
1657 WARNING("Timeout: no gypsy device created");
1658 server_create();
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,
1666 G_TYPE_INVALID);
1667 } else if (!device_connectionstatus) {
1668 WARNING("Timeout: device started but not connected");
1669 } else {
1670 GTimeVal tv;
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);
1680 return TRUE;
1684 /******************************************************************************/
1686 static void
1687 marshal_VOID__STRING_STRING_STRING(
1688 GClosure *closure,
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)(
1697 gpointer data1,
1698 const gchar *arg_1,
1699 const gchar *arg_2,
1700 const gchar *arg_3,
1701 gpointer data2);
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);
1712 } else {
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);
1720 callback(data1,
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),
1724 data2);
1727 static void
1728 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE(
1729 GClosure *closure,
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)(
1738 gpointer data1,
1739 gint arg_1,
1740 gint arg_2,
1741 gdouble arg_3,
1742 gdouble arg_4,
1743 gdouble arg_5,
1744 gpointer data2);
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);
1755 } else {
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);
1763 callback(data1,
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),
1769 data2);
1772 static void
1773 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE(
1774 GClosure *closure,
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)(
1783 gpointer data1,
1784 gint arg_1,
1785 gdouble arg_2,
1786 gdouble arg_3,
1787 gdouble arg_4,
1788 gpointer data2);
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);
1799 } else {
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);
1807 callback(data1,
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),
1812 data2);
1815 /******************************************************************************/
1817 static gboolean
1818 read_from_client(GIOChannel *source, GIOCondition condition, gpointer data)
1820 struct client *client;
1821 char buf[4096];
1822 gsize len = sizeof(buf);
1823 GIOStatus status;
1824 GString *reply;
1825 char *p;
1827 client = data;
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);
1837 g_free(client);
1838 g_io_channel_unref(source);
1840 if (!client_list && !nowait) {
1841 device_stop();
1844 return FALSE;
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);
1851 return TRUE;
1854 if (buf[len - 1] != '\n') {
1855 buf[len] = '\n';
1856 len++;
1859 buf[len] = '\0';
1861 reply = g_string_sized_new(128);
1862 g_string_assign(reply, "GPSD");
1864 p = buf;
1866 while (*p) {
1867 switch (toupper(*p++)) {
1868 case 'A':
1869 if (!POSITION_ALTITUDE_IS_VALID) {
1870 g_string_append(reply, ",A=?");
1871 } else {
1872 g_string_append_printf(reply, ",A=%.3f",
1873 position_altitude);
1875 break;
1876 case 'B':
1877 g_string_append(reply, ",B=?");
1878 break;
1879 case 'C':
1880 g_string_append(reply, ",C=1.00"); /* FIXME */
1881 break;
1882 case 'D':
1883 if (time_seconds <= 0) {
1884 g_string_append(reply, ",D=?");
1885 } else {
1886 struct tm *tm;
1887 time_t seconds;
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,
1896 tm->tm_sec);
1898 break;
1899 case 'E':
1900 g_string_append(reply, ",E=");
1902 if (!ACCURACY_PDOP_IS_VALID) {
1903 g_string_append(reply, "?");
1904 } else {
1905 g_string_append_printf(reply, "%.2f",
1906 accuracy_pdop);
1908 if (!ACCURACY_HDOP_IS_VALID) {
1909 g_string_append(reply, " ?");
1910 } else {
1911 g_string_append_printf(reply, " %.2f",
1912 accuracy_hdop);
1914 if (!ACCURACY_VDOP_IS_VALID) {
1915 g_string_append(reply, " ?");
1916 } else {
1917 g_string_append_printf(reply, " %.2f",
1918 accuracy_vdop);
1920 break;
1921 case 'F':
1922 if (*p == '=') {
1923 while (isprint(*p) && !isspace(*p)) {
1924 p++;
1927 g_string_append(reply, ",F=gypsy");
1928 break;
1929 case 'G':
1930 if (*p == '=') {
1931 p += strcspn(p, ",\r\n");
1933 g_string_append(reply, ",G=GPS");
1934 break;
1935 case 'I':
1936 g_string_append(reply, ",I=gypsy");
1937 break;
1938 case 'J':
1939 if (*p == '=') {
1940 p++;
1942 if (*p == '1' || *p == '+') {
1943 p++;
1944 g_string_append(reply, ",J=1");
1945 } else {
1946 if (*p == '0' || *p == '-') {
1947 p++;
1949 g_string_append(reply, ",J=0");
1951 break;
1952 case 'K':
1953 g_string_append(reply, ",K=1 gypsy");
1954 break;
1955 case 'L':
1956 g_string_append(reply, ",L=3 " VERSION
1957 " abcdefgijklmnopqrstuvwxyz");
1958 break;
1959 case 'M':
1960 g_string_append_printf(reply, ",M=%d",
1961 get_fixstatus());
1962 break;
1963 case 'N':
1964 g_string_append(reply, ",N=0");
1965 break;
1966 case 'O':
1967 add_info(reply);
1968 break;
1969 case 'P':
1970 if (!POSITION_LATITUDE_IS_VALID
1971 || !POSITION_LONGITUDE_IS_VALID) {
1972 g_string_append(reply, ",P=?");
1973 } else {
1974 g_string_append_printf(reply, ",P=%.6f %.6f",
1975 position_latitude, position_longitude);
1977 break;
1978 case 'Q':
1979 if (!ACCURACY_PDOP_IS_VALID
1980 && !ACCURACY_HDOP_IS_VALID
1981 && !ACCURACY_VDOP_IS_VALID) {
1982 g_string_append(reply, ",Q=?");
1983 } else {
1984 unsigned i, used;
1986 for (i = 0, used = 0; i < satellite_satellitec; i++) {
1987 if (satellite_satellitev[i].used) {
1988 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,
1997 0.0, 0.0);
1999 break;
2000 case 'R':
2001 if (*p == '=') {
2002 p++;
2004 if (*p == '2' || *p == '1' || *p == '+') {
2005 client->raw = TRUE;
2006 p++;
2007 } else if (*p == '0' || *p == '-') {
2008 client->raw = FALSE;
2009 p++;
2010 } else {
2011 client->raw = !client->raw;
2013 g_string_append_printf(reply, ",R=%1d", client->raw);
2014 break;
2015 case 'S':
2016 g_string_append_printf(reply, ",S=%d",
2017 MAX(get_fixstatus() - 1, 0));
2018 break;
2019 case 'T':
2020 if (!COURSE_DIRECTION_IS_VALID) {
2021 g_string_append(reply, ",T=?");
2022 } else {
2023 g_string_append_printf(reply, ",T=%.4f",
2024 course_direction);
2026 break;
2027 case 'U':
2028 if (!COURSE_CLIMB_IS_VALID) {
2029 g_string_append(reply, ",U=?");
2030 } else {
2031 g_string_append_printf(reply, ",U=%.3f",
2032 course_climb);
2034 break;
2035 case 'V':
2036 if (!COURSE_SPEED_IS_VALID) {
2037 g_string_append(reply, ",V=?");
2038 } else {
2039 g_string_append_printf(reply, ",V=%.3f",
2040 course_speed * KNOTS_TO_MPS);
2042 break;
2043 case 'W':
2044 if (*p == '=') {
2045 p++;
2047 if (*p == '1' || *p == '+') {
2048 client->watcher = TRUE;
2049 p++;
2050 } else if (*p == '0' || *p == '-') {
2051 client->watcher = FALSE;
2052 p++;
2053 } else {
2054 client->watcher = !client->watcher;
2056 g_string_append_printf(reply, ",W=%1d", client->watcher);
2057 break;
2058 case 'X':
2059 if (time_seconds <= 0) {
2060 g_string_append(reply, ",X=?");
2061 } else {
2062 g_string_append_printf(reply, ",X=%d.000000",
2063 time_seconds);
2065 break;
2066 case 'Y':
2067 add_sats(reply);
2068 break;
2069 case 'Z':
2070 g_string_append(reply, ",Z=?"); /* FIXME */
2071 break;
2072 case '$':
2073 g_string_append(reply, ",$=?"); /* FIXME */
2074 break;
2075 case '\r':
2076 case '\n':
2077 goto finish;
2078 default:
2079 break;
2083 finish:
2084 g_string_append(reply, "\r\n");
2085 send_to_client(client, reply->str, reply->len);
2086 g_string_free(reply, TRUE);
2087 return TRUE;
2090 static gboolean
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;
2096 int fd;
2098 MESSAGE("New client request");
2100 fd = accept(g_io_channel_unix_get_fd(source),
2101 (struct sockaddr *) &addr, &len);
2103 if (fd < 0) {
2104 ERROR("Cannot accept new connection: %s", strerror(errno));
2107 client = g_new0(struct client, 1);
2109 if (!client) {
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) {
2119 device_start();
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);
2134 return TRUE;
2137 static void
2138 init_tcp_service(const char *tcp_service)
2140 struct servent *pse;
2141 struct sockaddr_in addr;
2142 GIOChannel *channel;
2143 int fd, one = 1;
2145 memset(&addr, 0, sizeof(addr));
2147 addr.sin_family = AF_INET;
2148 addr.sin_addr.s_addr = INADDR_ANY;
2150 if (!tcp_service) {
2151 tcp_service = "2947";
2154 pse = getservbyname(tcp_service, "tcp");
2156 if (pse) {
2157 addr.sin_port = pse->s_port;
2158 } else {
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);
2168 if (fd < 0) {
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 /******************************************************************************/
2195 static void
2196 printerr_handler(const char *message)
2198 if (background) {
2199 syslog(LOG_USER | LOG_INFO, "%s", message);
2200 } else {
2201 fputs(message, stderr);
2205 static void
2206 log_handler(
2207 const char *domain,
2208 GLogLevelFlags level,
2209 const char *message,
2210 gpointer user_data
2213 const char *level_string;
2215 switch (level & G_LOG_LEVEL_MASK) {
2216 case G_LOG_LEVEL_ERROR:
2217 level_string = "ERROR: ";
2218 break;
2219 case G_LOG_LEVEL_CRITICAL:
2220 level_string = "CRITICAL: ";
2221 break;
2222 case G_LOG_LEVEL_WARNING:
2223 level_string = "WARNING: ";
2224 break;
2225 case G_LOG_LEVEL_MESSAGE:
2226 level_string = "MESSAGE: ";
2227 break;
2228 case G_LOG_LEVEL_INFO:
2229 level_string = "INFO: ";
2230 break;
2231 case G_LOG_LEVEL_DEBUG:
2232 level_string = "DEBUG: ";
2233 break;
2234 default:
2235 level_string = "";
2236 break;
2239 if (background) {
2240 if (domain) {
2241 syslog(LOG_USER | LOG_INFO, "%s: %s%s", domain,
2242 level_string, message);
2243 } else {
2244 syslog(LOG_USER | LOG_INFO, "%s%s",
2245 level_string, message);
2247 } else {
2248 struct timeval tv = { 0, 0 };
2249 struct tm *tm;
2250 char buf[64];
2251 size_t len;
2253 gettimeofday(&tv, NULL);
2254 tm = localtime(&tv.tv_sec);
2255 len = strftime(buf, sizeof(buf), "%T", tm);
2257 if (!len) {
2258 *buf = '\0';
2261 if (domain) {
2262 fprintf(stderr, "%s.%06li %s: %s%s\n", buf,
2263 (long) tv.tv_usec, domain, level_string,
2264 message);
2265 } else {
2266 fprintf(stderr, "%s.%06li %s%s\n", buf,
2267 (long) tv.tv_usec, level_string, message);
2272 /******************************************************************************/
2274 static void
2275 usage(void)
2277 printf("usage: "PACKAGE_NAME" [-n] [-N] [-D n] [-P pidfile] [-S port] [-h]\n\
2278 Options include:\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);
2304 opterr = 0;
2305 while (1) {
2306 int option;
2308 option = getopt(argc, argv, "F:D:S:bhNnP:VR:");
2310 if (option == -1) {
2311 break;
2314 switch (option) {
2315 case 'F':
2316 case 'b':
2317 case 'R':
2318 WARNING("Not implemented: -%c", option);
2319 break;
2320 case 'D':
2321 switch (atoi(optarg)) {
2322 case 0:
2323 log_level = G_LOG_LEVEL_ERROR
2324 | G_LOG_LEVEL_CRITICAL
2325 | G_LOG_LEVEL_WARNING;
2326 break;
2327 case 1:
2328 log_level = G_LOG_LEVEL_ERROR
2329 | G_LOG_LEVEL_CRITICAL
2330 | G_LOG_LEVEL_WARNING
2331 | G_LOG_LEVEL_MESSAGE;
2332 break;
2333 case 2:
2334 log_level = G_LOG_LEVEL_ERROR
2335 | G_LOG_LEVEL_CRITICAL
2336 | G_LOG_LEVEL_WARNING
2337 | G_LOG_LEVEL_MESSAGE
2338 | G_LOG_LEVEL_INFO;
2339 break;
2340 default:
2341 log_level = G_LOG_LEVEL_ERROR
2342 | G_LOG_LEVEL_CRITICAL
2343 | G_LOG_LEVEL_WARNING
2344 | G_LOG_LEVEL_MESSAGE
2345 | G_LOG_LEVEL_INFO
2346 | G_LOG_LEVEL_DEBUG;
2347 break;
2349 break;
2350 case 'N':
2351 foreground = TRUE;
2352 break;
2353 case 'S':
2354 tcp_service = optarg;
2355 break;
2356 case 'n':
2357 nowait = TRUE;
2358 break;
2359 case 'P':
2360 pid_file = optarg;
2361 break;
2362 case 'V':
2363 printf(PACKAGE_NAME" "VERSION"\n");
2364 exit(EXIT_SUCCESS);
2365 break;
2366 case 'h':
2367 case '?':
2368 default:
2369 usage();
2370 exit(EXIT_SUCCESS);
2371 break;
2375 if (!foreground) {
2376 pid_t pid;
2377 int fd;
2379 pid = fork();
2381 if (pid < 0) {
2382 ERROR("Cannot fork: %s", strerror(errno));
2383 } else if (pid > 0) {
2384 exit(EXIT_SUCCESS);
2387 openlog(PACKAGE_NAME, LOG_PID, LOG_USER);
2388 background = TRUE;
2390 setsid();
2391 chdir("/");
2393 fd = open("/dev/null", O_RDWR, 0);
2395 if (fd < 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);
2403 close(fd);
2406 if (pid_file) {
2407 FILE *fp;
2409 fp = fopen(pid_file, "w");
2411 if (!fp) {
2412 ERROR("Cannot fopen: %s: %s", pid_file, strerror(errno));
2415 fprintf(fp, "%u\n", (unsigned) getpid());
2416 fclose(fp);
2419 g_type_init();
2421 loop = g_main_loop_new(NULL, FALSE);
2423 connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
2425 if (!connection) {
2426 ERROR("Failed to open connection to system bus: %s\n",
2427 error->message);
2430 dbus_g_object_register_marshaller(
2431 marshal_VOID__STRING_STRING_STRING,
2432 G_TYPE_NONE,
2433 G_TYPE_STRING,
2434 G_TYPE_STRING,
2435 G_TYPE_STRING,
2436 G_TYPE_INVALID);
2437 dbus_g_object_register_marshaller(
2438 marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE,
2439 G_TYPE_NONE,
2440 G_TYPE_INT,
2441 G_TYPE_DOUBLE,
2442 G_TYPE_DOUBLE,
2443 G_TYPE_DOUBLE,
2444 G_TYPE_INVALID);
2445 dbus_g_object_register_marshaller(
2446 marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE,
2447 G_TYPE_NONE,
2448 G_TYPE_INT,
2449 G_TYPE_INT,
2450 G_TYPE_DOUBLE,
2451 G_TYPE_DOUBLE,
2452 G_TYPE_DOUBLE,
2453 G_TYPE_INVALID);
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",
2463 G_TYPE_STRING,
2464 G_TYPE_STRING,
2465 G_TYPE_STRING,
2466 G_TYPE_INVALID);
2467 dbus_g_proxy_connect_signal(proxy_dbus, "NameOwnerChanged",
2468 G_CALLBACK(name_owner_changed), NULL, NULL);
2470 server_create();
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);
2483 if (nowait) {
2484 timeout_handler_registered = TRUE;
2485 g_timeout_add(2000, timeout_handler, NULL);
2488 g_main_loop_run(loop);
2490 return 0;