From 7094b0fbbbf49a2339108edd7dc0af52841834e7 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Wed, 30 Oct 2013 23:11:40 -0400 Subject: Revert "Separate ntpd support from chrony support, step 1." We'll have to sneak up on this change more slowly. --- SConstruct | 6 +- driver_evermore.c | 6 +- driver_garmin.c | 24 +-- driver_geostar.c | 12 +- driver_italk.c | 6 +- driver_navcom.c | 6 +- driver_nmea2000.c | 6 +- driver_oncore.c | 12 +- driver_proto.c | 12 +- driver_sirf.c | 34 ++-- driver_superstar2.c | 6 +- driver_tsip.c | 12 +- driver_ubx.c | 6 +- driver_zodiac.c | 12 +- drivers.c | 102 +++++----- gpscap.ini | 22 +- gpscap.py | 10 +- gpsd.c | 23 +-- gpsd.h-tail | 18 +- libgpsd_core.c | 6 +- ntpshm.c | 505 ++++++++++++++++++++++++++++++++++++++++++++++ subframe.c | 4 +- timeexport.c | 507 ----------------------------------------------- www/writing-a-driver.xml | 19 +- 24 files changed, 676 insertions(+), 700 deletions(-) create mode 100644 ntpshm.c delete mode 100644 timeexport.c diff --git a/SConstruct b/SConstruct index 71fc4a62..b63c000a 100644 --- a/SConstruct +++ b/SConstruct @@ -123,7 +123,6 @@ boolopts = ( ("rtcm104v3", True, "rtcm104v3 support"), # Time service ("ntpshm", True, "NTP time hinting support"), - ("chrony", True, "chrony time hinting support"), ("pps", True, "PPS time syncing support"), # Export methods ("socket_export", True, "data export over sockets"), @@ -576,7 +575,8 @@ else: bluezlibs = [] env["bluez"] = False -if env['pps'] and config.CheckHeader("sys/timepps.h"): +# ntpshm is required for pps support +if env['pps'] and env['ntpshm'] and config.CheckHeader("sys/timepps.h"): confdefs.append("#define HAVE_SYS_TIMEPPS_H 1\n") announce("You have kernel PPS available.") else: @@ -966,7 +966,7 @@ env.StaticLibrary(target = 'libgps.a', source = libgps_sources) # Source groups -gpsd_sources = ['gpsd.c','timeexport.c','shmexport.c','dbusexport.c'] +gpsd_sources = ['gpsd.c','ntpshm.c','shmexport.c','dbusexport.c'] if env['systemd']: gpsd_sources.append("sd_socket.c") diff --git a/driver_evermore.c b/driver_evermore.c index a73317bf..50b4823f 100644 --- a/driver_evermore.c +++ b/driver_evermore.c @@ -633,9 +633,9 @@ const struct gps_type_t evermore_binary = #ifdef CONTROLSEND_ENABLE .control_send = evermore_control_send, /* how to send a control string */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(EVERMORE_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_garmin.c b/driver_garmin.c index e51beda0..32015573 100644 --- a/driver_garmin.c +++ b/driver_garmin.c @@ -1224,8 +1224,8 @@ static ssize_t garmin_control_send(struct gps_device_t *session, } #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE -static double garmin_time_offset(struct gps_device_t *session) +#ifdef NTPSHM_ENABLE +static double garmin_ntp_offset(struct gps_device_t *session) { if (session->sourcetype == source_usb) { return 0.035; /* Garmin USB, expect +/- 40mS jitter */ @@ -1244,7 +1244,7 @@ static double garmin_time_offset(struct gps_device_t *session) } return 0.430; /* WTF? WAG */ } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ /* this is everything we export */ #ifdef __UNUSED__ @@ -1391,9 +1391,9 @@ const struct gps_type_t garmin_usb_binary_old = #ifdef CONTROLSEND_ENABLE .control_send = garmin_control_send, /* send raw bytes */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = garmin_time_offset, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = garmin_ntp_offset, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* __UNUSED__ */ @@ -1420,9 +1420,9 @@ const struct gps_type_t garmin_usb_binary = #ifdef CONTROLSEND_ENABLE .control_send = garmin_control_send, /* send raw bytes */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = garmin_time_offset, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = garmin_ntp_offset, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ @@ -1448,9 +1448,9 @@ const struct gps_type_t garmin_ser_binary = #ifdef CONTROLSEND_ENABLE .control_send = garmin_control_send, /* send raw bytes */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = garmin_time_offset, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = garmin_ntp_offset, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_geostar.c b/driver_geostar.c index fd264d5f..d819e4ad 100644 --- a/driver_geostar.c +++ b/driver_geostar.c @@ -599,12 +599,12 @@ static void geostar_mode(struct gps_device_t *session, int mode) } #endif /* RECONFIGURE_ENABLE */ -#ifdef TIMESERVICE_ENABLE -static double geostar_time_offset(struct gps_device_t *session UNUSED) +#ifdef NTPSHM_ENABLE +static double geostar_ntp_offset(struct gps_device_t *session UNUSED) { return 0.31; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ /* this is everything we export */ /* *INDENT-OFF* */ @@ -629,9 +629,9 @@ const struct gps_type_t geostar_binary = #ifdef CONTROLSEND_ENABLE .control_send = geostar_control_send,/* how to send commands */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = geostar_time_offset, -#endif /* TIMESERVICE_ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = geostar_ntp_offset, +#endif /* NTPSHM_ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_italk.c b/driver_italk.c index 359614bb..2521351f 100644 --- a/driver_italk.c +++ b/driver_italk.c @@ -418,9 +418,9 @@ const struct gps_type_t italk_binary = #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* no control string sender */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(ITRAX_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_navcom.c b/driver_navcom.c index f04ce80a..5c6fbd24 100644 --- a/driver_navcom.c +++ b/driver_navcom.c @@ -1296,9 +1296,9 @@ const struct gps_type_t navcom_binary = #ifdef CONTROLSEND_ENABLE .control_send = navcom_control_send, /* how to send a control string */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_nmea2000.c b/driver_nmea2000.c index 562f37dd..68a942ae 100644 --- a/driver_nmea2000.c +++ b/driver_nmea2000.c @@ -1570,9 +1570,9 @@ const struct gps_type_t nmea2000 = { #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_oncore.c b/driver_oncore.c index 0179b53f..0152933a 100644 --- a/driver_oncore.c +++ b/driver_oncore.c @@ -454,8 +454,8 @@ static void oncore_event_hook(struct gps_device_t *session, event_t event) } } -#ifdef TIMESERVICE_ENABLE -static double oncore_time_offset(struct gps_device_t *session UNUSED) +#ifdef NTPSHM_ENABLE +static double oncore_ntp_offset(struct gps_device_t *session UNUSED) { /* * Only one sentence (NAVSOL) ships time. 0.175 seems best at @@ -464,7 +464,7 @@ static double oncore_time_offset(struct gps_device_t *session UNUSED) */ return 0.175; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ static gps_mask_t oncore_parse_input(struct gps_device_t *session) { @@ -503,9 +503,9 @@ const struct gps_type_t oncore_binary = { /* Control string sender - should provide checksum and headers/trailer */ .control_send = oncore_control_send, /* to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = oncore_time_offset, /* NTP offset array */ -#endif /* TIMESERVICE_ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = oncore_ntp_offset, /* NTP offset array */ +#endif /* NTPSHM_ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(ONCORE_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_proto.c b/driver_proto.c index f14e0e75..f9f7f060 100644 --- a/driver_proto.c +++ b/driver_proto.c @@ -453,8 +453,8 @@ static void _proto__set_mode(struct gps_device_t *session, int mode) } #endif /* RECONFIGURE_ENABLE */ -#ifdef TIMESERVICE_ENABLE -static double _proto_time_offset(struct gps_device_t *session) +#ifdef NTPSHM_ENABLE +static double _proto_ntp_offset(struct gps_device_t *session) { /* * If NTP notification is enabled, the GPS will occasionally NTP @@ -468,7 +468,7 @@ static double _proto_time_offset(struct gps_device_t *session) */ return MAGIC_CONSTANT; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ static void _proto__wrapup(struct gps_device_t *session) { @@ -525,9 +525,9 @@ const struct gps_type_t _proto__binary = { /* Control string sender - should provide checksum and headers/trailer */ .control_send = _proto__control_send, #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = _proto_time_offset, -#endif /* TIMESERVICE_ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = _proto_ntp_offset, +#endif /* NTPSHM_ENABLE */ /* *INDENT-ON* */ }; #endif /* defined(_PROTO__ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_sirf.c b/driver_sirf.c index 275bbc31..48902343 100644 --- a/driver_sirf.c +++ b/driver_sirf.c @@ -486,9 +486,9 @@ static gps_mask_t sirf_msg_swversion(struct gps_device_t *session, gpsd_report(session->context->debug, LOG_PROG, "SiRF: fv: %0.2f, Driver state flags are: %0x\n", fv, session->driver.sirf.driverstate); -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE session->driver.sirf.time_seen = 0; -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ gpsd_report(session->context->debug, LOG_DATA, "SiRF: FV MID 0x06: subtype='%s' mask={DEVICEID}\n", session->subtype); @@ -577,7 +577,7 @@ static gps_mask_t sirf_msg_svinfo(struct gps_device_t *session, && session->driver.sirf.dgps_source == SIRF_DGPS_SOURCE_SBAS) session->gpsdata.used[session->gpsdata.satellites_used++] = prn; } -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE if (st < 3) { gpsd_report(session->context->debug, LOG_PROG, "SiRF: NTPD not enough satellites seen: %d\n", st); @@ -589,15 +589,15 @@ static gps_mask_t sirf_msg_svinfo(struct gps_device_t *session, session->gpsdata.skyview_time, session->context->leap_seconds); } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ gpsd_report(session->context->debug, LOG_DATA, "SiRF: MTD 0x04: visible=%d mask={SATELLITE}\n", session->gpsdata.satellites_visible); return SATELLITE_SET; } -#ifdef TIMESERVICE_ENABLE -static double sirf_time_offset(struct gps_device_t *session) +#ifdef NTPSHM_ENABLE +static double sirf_ntp_offset(struct gps_device_t *session) /* return NTP time-offset fudge factor for this device */ { double retval = NAN; @@ -650,7 +650,7 @@ static double sirf_time_offset(struct gps_device_t *session) return retval; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ static gps_mask_t sirf_msg_navsol(struct gps_device_t *session, unsigned char *buf, size_t len) @@ -695,7 +695,7 @@ static gps_mask_t sirf_msg_navsol(struct gps_device_t *session, /* byte 21 is "mode 2", not clear how to interpret that */ session->newdata.time = gpsd_gpstime_resolve(session, (unsigned short)getbes16(buf, 22), (double)getbeu32(buf, 24) * 1e-2); -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE if (session->newdata.mode <= MODE_NO_FIX) { gpsd_report(session->context->debug, LOG_PROG, "SiRF: NTPD no fix, mode: %d\n", @@ -706,7 +706,7 @@ static gps_mask_t sirf_msg_navsol(struct gps_device_t *session, session->driver.sirf.time_seen, session->newdata.time, session->context->leap_seconds); } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ /* fix quality data */ session->gpsdata.dop.hdop = (double)getub(buf, 20) / 5.0; mask |= @@ -846,7 +846,7 @@ static gps_mask_t sirf_msg_geodetic(struct gps_device_t *session, gpsd_report(session->context->debug, LOG_PROG, "SiRF: GND 0x29 UTC: %lf\n", session->newdata.time); -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE if (session->newdata.mode <= MODE_NO_FIX) { gpsd_report(session->context->debug, LOG_PROG, "SiRF: NTPD no fix, mode: $d\n", @@ -864,7 +864,7 @@ static gps_mask_t sirf_msg_geodetic(struct gps_device_t *session, mask |= PPSTIME_IS; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ /* skip 4 bytes of satellite map */ session->newdata.altitude = getbes32(buf, 35) * 1e-2; /* skip 1 byte of map datum */ @@ -979,7 +979,7 @@ static gps_mask_t sirf_msg_ublox(struct gps_device_t *session, /*@ -compdef */ session->newdata.time = (timestamp_t)mkgmtime(&unpacked_date) + subseconds; /*@ +compdef */ -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE if (0 == (session->driver.sirf.time_seen & TIME_SEEN_UTC_2)) { gpsd_report(session->context->debug, LOG_RAW, "SiRF: NTPD just SEEN_UTC_2\n"); @@ -988,7 +988,7 @@ static gps_mask_t sirf_msg_ublox(struct gps_device_t *session, "SiRF: NTPD valid time MID 0x62, seen=0x%02x\n", session->driver.sirf.time_seen); session->driver.sirf.time_seen |= TIME_SEEN_UTC_2; -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ session->context->valid |= LEAP_SECOND_VALID; } @@ -1034,7 +1034,7 @@ static gps_mask_t sirf_msg_ppstime(struct gps_device_t *session, /*@ +compdef */ session->context->leap_seconds = (int)getbeu16(buf, 8); session->context->valid |= LEAP_SECOND_VALID; -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE if (0 == (session->driver.sirf.time_seen & TIME_SEEN_UTC_2)) { gpsd_report(session->context->debug, LOG_RAW, "SiRF: NTPD just SEEN_UTC_2\n"); @@ -1044,7 +1044,7 @@ static gps_mask_t sirf_msg_ppstime(struct gps_device_t *session, session->driver.sirf.time_seen, session->context->leap_seconds); session->driver.sirf.time_seen |= TIME_SEEN_UTC_2; -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ mask |= TIME_SET; if ( 3 <= session->gpsdata.satellites_visible ) { mask |= PPSTIME_IS; @@ -1385,8 +1385,8 @@ const struct gps_type_t sirf_binary = #ifdef CONTROLSEND_ENABLE .control_send = sirf_control_send,/* how to send a control string */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = sirf_time_offset, +#ifdef NTPSHM_ENABLE + .ntp_offset = sirf_ntp_offset, #endif /* NTP_SHM_ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_superstar2.c b/driver_superstar2.c index d98fa697..31a8658c 100644 --- a/driver_superstar2.c +++ b/driver_superstar2.c @@ -575,9 +575,9 @@ const struct gps_type_t superstar2_binary = { /* Control string sender - should provide checksum and trailer */ .control_send = superstar2_control_send, #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_tsip.c b/driver_tsip.c index ddc79395..087dfccf 100644 --- a/driver_tsip.c +++ b/driver_tsip.c @@ -1151,13 +1151,13 @@ static void tsip_mode(struct gps_device_t *session, int mode) } #endif /* RECONFIGURE_ENABLE */ -#ifdef TIMESERVICE_ENABLE -static double tsip_time_offset(struct gps_device_t *session UNUSED) +#ifdef NTPSHM_ENABLE +static double tsip_ntp_offset(struct gps_device_t *session UNUSED) { /* FIX-ME: is a constant offset right here? */ return 0.075; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ void configuration_packets_generic(struct gps_device_t *session) /* configure generic Trimble TSIP device to a known state */ @@ -1274,9 +1274,9 @@ const struct gps_type_t tsip_binary = #ifdef CONTROLSEND_ENABLE .control_send = tsip_control_send,/* how to send commands */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = tsip_time_offset, -#endif /* TIMESERVICE_ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = tsip_ntp_offset, +#endif /* NTPSHM_ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_ubx.c b/driver_ubx.c index a8f414c1..d1bda91d 100644 --- a/driver_ubx.c +++ b/driver_ubx.c @@ -840,9 +840,9 @@ const struct gps_type_t ubx_binary = { #ifdef CONTROLSEND_ENABLE .control_send = ubx_control_send, /* no control sender yet */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(UBX_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_zodiac.c b/driver_zodiac.c index 5ab969a1..296dbece 100644 --- a/driver_zodiac.c +++ b/driver_zodiac.c @@ -445,8 +445,8 @@ static bool zodiac_speed_switch(struct gps_device_t *session, } #endif /* RECONFIGURE_ENABLE */ -#ifdef TIMESERVICE_ENABLE -static double zodiac_time_offset(struct gps_device_t *session UNUSED) +#ifdef NTPSHM_ENABLE +static double zodiac_ntp_offset(struct gps_device_t *session UNUSED) { /* Removing/changing the magic number below is likely to disturb * the handling of the 1pps signal from the gps device. The regression @@ -454,7 +454,7 @@ static double zodiac_time_offset(struct gps_device_t *session UNUSED) * with the 1pps signal active is required. */ return 1.1; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ /* this is everything we export */ /* *INDENT-OFF* */ @@ -479,9 +479,9 @@ const struct gps_type_t zodiac_binary = #ifdef CONTROLSEND_ENABLE .control_send = zodiac_control_send, /* for gpsctl and friends */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = zodiac_time_offset, /* compute NTO fudge factor */ -#endif /* TIMESERVICE_ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = zodiac_ntp_offset, /* compute NTO fudge factor */ +#endif /* NTPSHM_ENABLE */ }; /* *INDENT-ON* */ diff --git a/drivers.c b/drivers.c index 52d130bf..e55d8790 100644 --- a/drivers.c +++ b/drivers.c @@ -101,9 +101,9 @@ const struct gps_type_t unknown = { #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ @@ -265,9 +265,9 @@ const struct gps_type_t nmea = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ @@ -366,9 +366,9 @@ const struct gps_type_t garmin = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* GARMIN_ENABLE && NMEA_ENABLE */ @@ -428,9 +428,9 @@ const struct gps_type_t ashtech = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* ASHTECH_ENABLE */ @@ -479,9 +479,9 @@ const struct gps_type_t fv18 = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* FV18_ENABLE */ @@ -533,9 +533,9 @@ const struct gps_type_t gpsclock = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* GPSCLOCK_ENABLE */ @@ -588,9 +588,9 @@ static const struct gps_type_t tripmate = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* TRIPMATE_ENABLE */ @@ -639,9 +639,9 @@ static const struct gps_type_t earthmate = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* never actually used. */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /*@ -redef @*/ /* *INDENT-ON* */ @@ -762,9 +762,9 @@ const struct gps_type_t trueNorth = { #ifdef CONTROLSEND_ENABLE .control_send = tnt_control_send, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif @@ -840,9 +840,9 @@ static const struct gps_type_t oceanServer = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif @@ -907,9 +907,9 @@ static const struct gps_type_t fury = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ @@ -961,9 +961,9 @@ static const struct gps_type_t rtcm104v2 = { #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* RTCM104V2_ENABLE */ @@ -1007,9 +1007,9 @@ static const struct gps_type_t rtcm104v3 = { #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* RTCM104V3_ENABLE */ @@ -1042,9 +1042,9 @@ static const struct gps_type_t garmintxt = { #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* GARMINTXT_ENABLE */ @@ -1130,9 +1130,9 @@ const struct gps_type_t mtk3301 = { #ifdef CONTROLSEND_ENABLE .control_send = nmea_write, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* MTK3301_ENABLE */ @@ -1368,9 +1368,9 @@ const struct gps_type_t aivdm = { #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* no control sender */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no NTP communication */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no NTP communication */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ #endif /* AIVDM_ENABLE */ @@ -1466,9 +1466,9 @@ const struct gps_type_t json_passthrough = { #ifdef CONTROLSEND_ENABLE .control_send = NULL, /* how to send control strings */ #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - .time_offset = NULL, /* no method for NTP fudge factor */ -#endif /* ENABLE ENABLE */ +#ifdef NTPSHM_ENABLE + .ntp_offset = NULL, /* no method for NTP fudge factor */ +#endif /* NTPSHM_ ENABLE */ }; /* *INDENT-ON* */ diff --git a/gpscap.ini b/gpscap.ini index 8c2bc308..533150e4 100644 --- a/gpscap.ini +++ b/gpscap.ini @@ -24,7 +24,7 @@ # usbchip = USB I/O chipset # pps = supports pulse-per-second precision time reporting # pps_accuracy = claimed PPS accuracy -# time_offset = NTP offset +# ntp_offset = NTP offset # configurable = can the device be bricked by speed changes? # tested = last gpsd tested, or "regression" if we have a test load # nmea = NMEA version this emits, if known @@ -871,7 +871,7 @@ nmea = 2.0 and 2.3 packaging = mouse pps = True pps_accuracy = 1us -time_offset = 0.125s +ntp_offset = 0.125s submitter = Gary E. Miller techdoc = http://www.garmin.com/manuals/GPS18_TechnicalSpecification.pdf tested = 2.5 @@ -1162,7 +1162,7 @@ nmea = 3.01 packaging = mouse pps = True pps_accuracy = 50ns -time_offset = ? +ntp_offset = ? rating = excellent submitter = Gary E. Miller , Tony Hain techdoc = http://www.usglobalsat.com/p-58-mr-350p-bulkhead.aspx @@ -1425,7 +1425,7 @@ firmware = 2.18 interfaces = RS-232 pps = True pps_accuracy = 50ns -time_offset = ? +ntp_offset = ? model = FireFly-1A and FireFly-II GPSDO notes = Uses uBlox Antaris 5 with Kick Start and Super Sense, soon movingto uBlox-6. Defective \r\r\n string terminations @@ -1530,7 +1530,7 @@ tested = regression rating = good pps = True pps_accuracy = 250ns -time_offset = ? +ntp_offset = ? submitter = Chris Kuethe notes = Receiver comes up in silent mode, you may need to use ashctl to turn on a default set of messages. Tested with firmware BQ00 and BQ04. @@ -1565,7 +1565,7 @@ tested = 2.20 nmea = 2.2 pps = True pps_accuracy = 50ns -time_offset = ? +ntp_offset = ? rating = good discontinued = True submitter = Wojciech Kazubski @@ -1612,7 +1612,7 @@ interfaces = USB tested = 3.9 pps = True pps_accuracy = 1ms -time_offset = ? +ntp_offset = ? rating = excellent submitter = Eric S. Raymond . notes = Also known as the Macx-1, this is the USB variant of the @@ -2266,7 +2266,7 @@ engine = Colossus RF ASIC, IO-C33 (Epson C33 RISC) interfaces = USB,RS-232 pps = True pps_accuracy = 50ns -time_offset = 0.675s +ntp_offset = 0.675s usbchip = CP2102 tested = regression rating = good @@ -2332,7 +2332,7 @@ interfaces = USB,UART tested = regression pps = True pps_accuracy = 50ns -time_offset = ? +ntp_offset = ? submitter = Chris Kuethe [EVK-5H-0] @@ -2355,7 +2355,7 @@ date = 2011-02-02 interfaces = TTL pps = True pps_accuracy = 50ns -time_offset = ? +ntp_offset = ? location = Adelaide, AU, 34.9S, 138.6E model = LEA 5Q notes = Sample contains GPGST (pseudorange noise statistics). @@ -2379,7 +2379,7 @@ model = EVK-6H-0 packaging = other rating = excellent pps_accuracy = 50ns -time_offset = ? +ntp_offset = ? submitter = Eric S. Raymond techdoc = http://www.u-blox.com/images/downloads/Product_Docs/u-blox6_ReceiverDescriptionProtocolSpec_%28GPS.G6-SW-10018%29.pdf vendor = uBlox diff --git a/gpscap.py b/gpscap.py index 423cea17..b00f46c7 100644 --- a/gpscap.py +++ b/gpscap.py @@ -139,13 +139,13 @@ class GPSDictionary(ConfigParser.RawConfigParser): nmea = self.get(dev, "nmea") ofp.write("%s\n" % nmea) if self.has_option(dev, "pps") and self.get(dev, "pps") == "True": - pps_accuracy = time_offset = "" + pps_accuracy = ntp_offset = "" if self.has_option(dev, "pps_accuracy"): pps_accuracy = self.get(dev, "pps_accuracy") - if self.has_option(dev, "time_offset"): - time_offset = self.get(dev, "time_offset") - if pps_accuracy and time_offset: - ofp.write("%s
%s\n" % (pps_accuracy, time_offset)) + if self.has_option(dev, "ntp_offset"): + ntp_offset = self.get(dev, "ntp_offset") + if pps_accuracy and ntp_offset: + ofp.write("%s
%s\n" % (pps_accuracy, ntp_offset)) else: ofp.write("?
\n") else: diff --git a/gpsd.c b/gpsd.c index 8c1e1bf1..f31d07eb 100644 --- a/gpsd.c +++ b/gpsd.c @@ -223,9 +223,6 @@ static void typelist(void) #if defined(NTPSHM_ENABLE) (void)printf("# NTPSHM for NTPd enabled.\n"); #endif -#if defined(CHRONY_ENABLE) - (void)printf("# Chrony support enabled.\n"); -#endif #if defined(PPS_ENABLE) (void)printf("# PPS enabled.\n"); #endif @@ -666,9 +663,9 @@ static void deactivate_device(struct gps_device_t *device) adjust_max_fd(device->gpsdata.gps_fd, false); #if defined(PPS_ENABLE) && defined(TIOCMIWAIT) #endif /* defined(PPS_ENABLE) && defined(TIOCMIWAIT) */ -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE ntpd_link_deactivate(device); -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ gpsd_deactivate(device); } } @@ -720,7 +717,7 @@ bool gpsd_add_device(const char *device_name, bool flag_nowait) for (devp = devices; devp < devices + MAXDEVICES; devp++) if (!allocated_device(devp)) { gpsd_init(devp, &context, device_name); -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE /* * Now is the right time to grab the shared memory segment(s) * to communicate the navigation message derived and (possibly) @@ -735,7 +732,7 @@ bool gpsd_add_device(const char *device_name, bool flag_nowait) "NTPD ntpd_link_activate: %d\n", (int)devp->shmindex >= 0); -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ gpsd_report(context.debug, LOG_INF, "stashing device %s at slot %d\n", device_name, (int)(devp - devices)); @@ -1511,7 +1508,7 @@ static void all_reports(struct gps_device_t *device, gps_mask_t changed) } -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE /* * Time is eligible for shipping to NTPD if the driver has * asserted PPSTIME_IS at any point in the current cycle. @@ -1539,14 +1536,14 @@ static void all_reports(struct gps_device_t *device, gps_mask_t changed) //gpsd_report(context.debug, LOG_PROG, "NTP: Got one\n"); /* assume zero when there's no offset method */ if (device->device_type == NULL - || device->device_type->time_offset == NULL) + || device->device_type->ntp_offset == NULL) offset = 0.0; else - offset = device->device_type->time_offset(device); + offset = device->device_type->ntp_offset(device); (void)ntpshm_put(device, device->newdata.time, offset); device->last_fixtime = device->newdata.time; } -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ /* * If no reliable end of cycle, must report every time @@ -1949,7 +1946,7 @@ int main(int argc, char *argv[]) gpsd_report(context.debug, LOG_INF, "listening on port %s\n", gpsd_service); #endif /* SOCKET_EXPORT_ENABLE */ -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE if (getuid() == 0) { errno = 0; // nice() can ONLY succeed when run as root! @@ -1963,7 +1960,7 @@ int main(int argc, char *argv[]) * to use segments 0 and 1. */ (void)ntpshm_init(&context); -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ #if defined(DBUS_EXPORT_ENABLE) && !defined(S_SPLINT_S) /* we need to connect to dbus as root */ diff --git a/gpsd.h-tail b/gpsd.h-tail index 2ff8b5e8..a11bcac3 100644 --- a/gpsd.h-tail +++ b/gpsd.h-tail @@ -36,10 +36,6 @@ #include #endif -#if defined(ENABLE_NTPSHM) || defined(ENABLE_CHRONY) -#define TIMESERVICE_ENABLE -#endif - #ifdef _WIN32 typedef unsigned int speed_t; #endif @@ -243,14 +239,12 @@ struct gps_context_t { double gps_tow; /* GPS time of week, actually 19 bits */ int century; /* for NMEA-only devices without ZDA */ int rollovers; /* rollovers since start of run */ -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE int leap_notify; /* notification state from subframe */ #define LEAP_NOWARNING 0x0 /* normal, no leap second warning */ #define LEAP_ADDSECOND 0x1 /* last minute of day has 60 seconds */ #define LEAP_DELSECOND 0x2 /* last minute of day has 59 seconds */ #define LEAP_NOTINSYNC 0x3 /* overload, clock is free running */ -#endif /* TIMESERVICE_ENABLE */ -#ifdef NTPSHM_ENABLE bool enable_ntpshm; /* we need the volatile here to tell the C compiler not to * 'optimize' as 'dead code' the writes to SHM */ @@ -354,9 +348,9 @@ struct gps_type_t { #ifdef CONTROLSEND_ENABLE /*@null@*/ssize_t (*control_send)(struct gps_device_t *session, char *buf, size_t buflen); #endif /* CONTROLSEND_ENABLE */ -#ifdef TIMESERVICE_ENABLE - /*@null@*/double (*time_offset)(struct gps_device_t *session); -#endif /* TIMESERVICE_ENABLE */ +#ifdef NTPSHM_ENABLE + /*@null@*/double (*ntp_offset)(struct gps_device_t *session); +#endif /* NTPSHM_ENABLE */ }; /* @@ -477,6 +471,7 @@ struct gps_device_t { #if defined(HAVE_SYS_TIMEPPS_H) pps_handle_t kernelpps_handle; #endif /* defined(HAVE_SYS_TIMEPPS_H) */ + int chronyfd; /* for talking to chrony */ /*@null@*/ void (*thread_init_hook)(struct gps_device_t *); /*@null@*/ void (*thread_error_hook)(struct gps_device_t *); /*@null@*/ char *(*thread_report_hook)(struct gps_device_t *, @@ -485,9 +480,6 @@ struct gps_device_t { double); /*@null@*/ void (*thread_wrap_hook)(struct gps_device_t *); #endif /* PPS_ENABLE */ -#ifdef CHRONY_ENABLE - int chronyfd; /* for talking to chrony */ -#endif /* CHRONY_ENABLE */ double mag_var; /* magnetic variation in degrees */ bool back_to_nmea; /* back to NMEA on revert? */ char msgbuf[MAX_PACKET_LENGTH*2+1]; /* command message buffer for sends */ diff --git a/libgpsd_core.c b/libgpsd_core.c index f294d848..4a3a92e6 100644 --- a/libgpsd_core.c +++ b/libgpsd_core.c @@ -231,17 +231,15 @@ void gps_context_init(struct gps_context_t *context) .gps_tow = 0, .century = 0, .rollovers = 0, -#ifdef TIMESERVICE_ENABLE - .leap_notify = LEAP_NOWARNING, -#endif /* TIMESERVICE_ENABLE */ #ifdef NTPSHM_ENABLE + .leap_notify = LEAP_NOWARNING, .enable_ntpshm = false, .shmTime = {0}, .shmTimeInuse = {0}, -#endif /* NTPSHM_ENABLE */ # ifdef PPS_ENABLE .pps_hook = NULL, # endif /* PPS_ENABLE */ +#endif /* NTPSHM_ENABLE */ #ifdef SHM_EXPORT_ENABLE .shmexport = NULL, #endif /* SHM_EXPORT_ENABLE */ diff --git a/ntpshm.c b/ntpshm.c new file mode 100644 index 00000000..5fe96af3 --- /dev/null +++ b/ntpshm.c @@ -0,0 +1,505 @@ +/* + * ntpshm.c - put time information in SHM segment for xntpd, or to chrony + * + * struct shmTime and getShmTime from file in the xntp distribution: + * sht.c - Testprogram for shared memory refclock + * + * This file is Copyright (c) 2010 by the GPSD project BSD terms apply: + * see the file COPYING in the distribution root for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#ifndef S_SPLINT_S +#include +#include +#include +#endif /* S_SPLINT_S */ + +#include "gpsd.h" + +#ifdef NTPSHM_ENABLE +#include +#include +#include + +#define NTPD_BASE 0x4e545030 /* "NTP0" */ +#define SHM_UNIT 0 /* SHM driver unit number (0..3) */ + +#define PPS_MIN_FIXES 3 /* # fixes to wait for before shipping PPS */ + +struct shmTime +{ + int mode; /* 0 - if valid set + * use values, + * clear valid + * 1 - if valid set + * if count before and after read of values is equal, + * use values + * clear valid + */ + int count; + time_t clockTimeStampSec; + int clockTimeStampUSec; + time_t receiveTimeStampSec; + int receiveTimeStampUSec; + int leap; + int precision; + int nsamples; + int valid; + int pad[10]; +}; + +/* Note: you can start gpsd as non-root, and have it work with ntpd. + * However, it will then only use the ntpshm segments 2 and 3. + * + * Ntpd always runs as root (to be able to control the system clock). + * Its logics for the creation of ntpshm segments are: + * + * Segments 0 and 1: permissions 0600, i.e. other programs can only + * read and write as root. + * + * Segments 2 and 3: permissions 0666, i.e. other programs can read + * and write as any user. I.e.: if ntpd has been + * configured to use these segments, any + * unpriviliged user is allowed to provide data + * for synchronisation. + * * As gpsd can be started as both root and non-root, this behaviour is + * mimicked by: + * + * Started as root: do as ntpd when attaching (creating) the segments. + * (In contrast to ntpd, which only attaches (creates) configured + * segments, gpsd creates all segments.) + * + * Started as non-root: only attach (create) segments 2 and 3 with + * permissions 0666. As the permissions are for any user, the creator + * does not matter. + * + * For each GPS module gpsd controls, it will use the attached ntpshm + * segments in pairs (for coarse clock and pps source, respectively) + * starting from the first found segments. I.e. started as root, one + * GPS will deliver data on segments 0 and 1, and as non-root data + * will be delivered on segments 2 and 3. + * + * to debug, try looking at the live segments this way + * + * ipcs -m + * + * results should look like this: + * ------ Shared Memory Segments -------- + * key shmid owner perms bytes nattch status + * 0x4e545030 0 root 700 96 2 + * 0x4e545031 32769 root 700 96 2 + * 0x4e545032 163842 root 666 96 1 + * 0x4e545033 196611 root 666 96 1 + * + * For a bit more data try this: + * cat /proc/sysvipc/shm + * + * If gpsd can not open the segments be sure you are not running SELinux + * or apparmor. + * + * if you see the shared segments (keys 1314148400 -- 1314148403), and + * no gpsd or ntpd is running then try removing them like this: + * + * ipcrm -M 0x4e545030 + * ipcrm -M 0x4e545031 + * ipcrm -M 0x4e545032 + * ipcrm -M 0x4e545033 + */ +static /*@null@*/ volatile struct shmTime *getShmTime(struct gps_context_t *context, int unit) +{ + int shmid; + unsigned int perms; + volatile struct shmTime *p; + // set the SHM perms the way ntpd does + if (unit < 2) { + // we are root, be careful + perms = 0600; + } else { + // we are not root, try to work anyway + perms = 0666; + } + + /* + * Note: this call requires root under BSD, and possibly on + * well-secured Linux systems. This is why ntpshm_init() has to be + * called before privilege-dropping. + */ + shmid = shmget((key_t) (NTPD_BASE + unit), + sizeof(struct shmTime), (int)(IPC_CREAT | perms)); + if (shmid == -1) { + gpsd_report(context->debug, LOG_ERROR, + "NTPD shmget(%ld, %zd, %o) fail: %s\n", + (long int)(NTPD_BASE + unit), sizeof(struct shmTime), + (int)perms, strerror(errno)); + return NULL; + } + p = (struct shmTime *)shmat(shmid, 0, 0); + /*@ -mustfreefresh */ + if ((int)(long)p == -1) { + gpsd_report(context->debug, LOG_ERROR, + "NTPD shmat failed: %s\n", + strerror(errno)); + return NULL; + } + gpsd_report(context->debug, LOG_PROG, + "NTPD shmat(%d,0,0) succeeded, segment %d\n", + shmid, unit); + return p; + /*@ +mustfreefresh */ +} + +void ntpshm_init(struct gps_context_t *context) +/* Attach all NTP SHM segments. Called once at startup, while still root. */ +{ + int i; + + for (i = 0; i < NTPSHMSEGS; i++) { + // Only grab the first two when running as root. + if (2 <= i || 0 == getuid()) { + context->shmTime[i] = getShmTime(context, i); + } + } + memset(context->shmTimeInuse, 0, sizeof(context->shmTimeInuse)); + context->enable_ntpshm = true; +} + +static int ntpshm_alloc(struct gps_context_t *context) +/* allocate NTP SHM segment. return its segment number, or -1 */ +{ + int i; + + for (i = 0; i < NTPSHMSEGS; i++) + if (context->shmTime[i] != NULL && !context->shmTimeInuse[i]) { + context->shmTimeInuse[i] = true; + + /* + * In case this segment gets sent to ntpd before an + * ephemeris is available, the LEAP_NOTINSYNC value will + * tell ntpd that this source is in a "clock alarm" state + * and should be ignored. The goal is to prevent ntpd + * from declaring the GPS a falseticker before it gets + * all its marbles together. + */ + memset((void *)context->shmTime[i], 0, sizeof(struct shmTime)); + context->shmTime[i]->mode = 1; + context->shmTime[i]->leap = LEAP_NOTINSYNC; + context->shmTime[i]->precision = -1; /* initially 0.5 sec */ + context->shmTime[i]->nsamples = 3; /* stages of median filter */ + + return i; + } + + return -1; +} + +static bool ntpshm_free(struct gps_context_t * context, int segment) +/* free NTP SHM segment */ +{ + if (segment < 0 || segment >= NTPSHMSEGS) + return false; + + context->shmTimeInuse[segment] = false; + return true; +} + +int ntpshm_put(struct gps_device_t *session, double fixtime, double fudge) +/* put a received fix time into shared memory for NTP */ +{ + /* shmTime is volatile to try to prevent C compiler from reordering + * writes, or optimizing some 'dead code'. but CPU cache may still + *write out of order since we do not use memory barriers, yet */ + volatile struct shmTime *shmTime = NULL; + struct timeval tv; + double seconds, microseconds; + + // gpsd_report(session->context->debug, LOG_PROG, "NTP: doing ntpshm_put(,%g, %g)\n", fixtime, fudge); + if (session->shmindex < 0 || + (shmTime = session->context->shmTime[session->shmindex]) == NULL) { + gpsd_report(session->context->debug, LOG_RAW, + "NTPD missing shm\n"); + return 0; + } + + (void)gettimeofday(&tv, NULL); + fixtime += fudge; + microseconds = 1000000.0 * modf(fixtime, &seconds); + if (shmTime->clockTimeStampSec == (time_t) seconds) { + gpsd_report(session->context->debug, LOG_RAW, + "NTPD ntpshm_put: skipping duplicate second\n"); + return 0; + } + + /* we use the shmTime mode 1 protocol + * + * ntpd does this: + * + * reads valid. + * IFF valid is 1 + * reads count + * reads values + * reads count + * IFF count unchanged + * use values + * clear valid + * + */ + shmTime->valid = 0; + shmTime->count++; + /* FIXME need a memory barrier here to prevent write reordering by + * the compiler or CPU cache */ + shmTime->clockTimeStampSec = (time_t) seconds; + shmTime->clockTimeStampUSec = (int)microseconds; + shmTime->receiveTimeStampSec = (time_t) tv.tv_sec; + shmTime->receiveTimeStampUSec = (int)tv.tv_usec; + shmTime->leap = session->context->leap_notify; + /* setting the precision here does not seem to help anything, too + * hard to calculate properly anyway. Let ntpd figure it out. + * Any NMEA will be about -1 or -2. + * Garmin GPS-18/USB is around -6 or -7. + */ + /* FIXME need a memory barrier here to prevent write reordering by + * the compiler or CPU cache */ + shmTime->count++; + shmTime->valid = 1; + + gpsd_report(session->context->debug, LOG_RAW, + "NTPD ntpshm_put: Clock: %lu.%06lu @ %lu.%06lu, fudge: %0.3f\n", + (unsigned long)seconds, (unsigned long)microseconds, + (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec, fudge); + + return 1; +} + +#ifdef PPS_ENABLE +/*@unused@*//* splint is confused here */ +/* put NTP shared memory info based on received PPS pulse + * + * good news is that kernel PPS gives us nSec resolution + * bad news is that ntpshm only has uSec resolution + * + * actual_tv is the actual time we think the PPS happened + * ts is the time we saw the pulse + */ +static int ntpshm_pps(struct gps_device_t *session, struct timeval *actual_tv, + struct timespec *ts) +{ + volatile struct shmTime *shmTime = NULL, *shmTimeP = NULL; + struct timeval tv; + int precision; + double offset; + + if (0 > session->shmindex || 0 > session->shmTimeP || + (shmTime = session->context->shmTime[session->shmindex]) == NULL || + (shmTimeP = session->context->shmTime[session->shmTimeP]) == NULL) + return 0; + + /* for now we use uSec, not nSec */ + /*@-type@*//* splint is confused about struct timespec */ + TSTOTV( &tv, ts ); + /*@+type@*/ + + /* we use the shmTime mode 1 protocol + * + * ntpd does this: + * + * reads valid. + * IFF valid is 1 + * reads count + * reads values + * reads count + * IFF count unchanged + * use values + * clear valid + * + */ + shmTimeP->valid = 0; + shmTimeP->count++; + shmTimeP->clockTimeStampSec = (time_t)actual_tv->tv_sec; + shmTimeP->clockTimeStampUSec = (int)actual_tv->tv_usec; + shmTimeP->receiveTimeStampSec = (time_t)tv.tv_sec; + shmTimeP->receiveTimeStampUSec = (int)tv.tv_usec; + shmTimeP->leap = session->context->leap_notify; + /* precision is a placebo, ntpd does not really use it + * real world accuracy is around 16uS, thus -16 precision */ + shmTimeP->precision = -16; + shmTimeP->count++; + shmTimeP->valid = 1; + + /* this is more an offset jitter/dispersion than precision, + * but still useful for debug */ + offset = fabs((double)(tv.tv_sec - actual_tv->tv_sec) + + ((double)(tv.tv_usec - actual_tv->tv_usec) / 1000000.0)); + precision = offset != 0 ? (int)(ceil(log(offset) / M_LN2)) : -20; + /*@-type@*//* splint is confused about struct timespec */ + gpsd_report(session->context->debug, LOG_RAW, + "PPS ntpshm_pps %lu.%03lu @ %lu.%09lu, preci %d\n", + (unsigned long)actual_tv->tv_sec, + (unsigned long)actual_tv->tv_usec, + (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec, + precision); + /*@+type@*/ + return 1; +} + +#define SOCK_MAGIC 0x534f434b +struct sock_sample { + struct timeval tv; + double offset; + int pulse; + int leap; + /* cppcheck-suppress unusedStructMember */ + int _pad; + int magic; /* must be SOCK_MAGIC */ +}; + +/*@-mustfreefresh@*/ +static void init_hook(struct gps_device_t *session) +/* for chrony SOCK interface, which allows nSec timekeeping */ +{ + /* open the chrony socket */ + char chrony_path[PATH_MAX]; + + session->chronyfd = -1; + if ( 0 == getuid() ) { + /* this case will fire on command-line devices; + * they're opened before priv-dropping. Matters because + * only root can use /var/run. + */ + (void)snprintf(chrony_path, sizeof (chrony_path), + "/var/run/chrony.%s.sock", basename(session->gpsdata.dev.path)); + } else { + (void)snprintf(chrony_path, sizeof (chrony_path), + "/tmp/chrony.%s.sock", basename(session->gpsdata.dev.path)); + } + + if (access(chrony_path, F_OK) != 0) { + gpsd_report(session->context->debug, LOG_PROG, + "PPS chrony socket %s doesn't exist\n", chrony_path); + } else { + session->chronyfd = netlib_localsocket(chrony_path, SOCK_DGRAM); + if (session->chronyfd < 0) + gpsd_report(session->context->debug, LOG_PROG, + "PPS connect chrony socket failed: %s, error: %d, errno: %d/%s\n", + chrony_path, session->chronyfd, errno, strerror(errno)); + else + gpsd_report(session->context->debug, LOG_RAW, + "PPS using chrony socket: %s\n", chrony_path); + } +} +/*@+mustfreefresh@*/ + + +/* actual_tv is when we think the PPS pulse wass */ +/* ts is the local clocke time we saw the pulse */ +/* offset is actual_tv - tv */ +static void chrony_send(struct gps_device_t *session, + struct timeval *actual_tv, + struct timespec *ts UNUSED, double offset) +{ + struct sock_sample sample; + + /* FIXME!! offset is double of the error from local time */ + /* chrony expects tv-sec since Jan 1970 */ + sample.pulse = 0; + sample.leap = session->context->leap_notify; + sample.magic = SOCK_MAGIC; + sample.tv = *actual_tv; /* structure copy */ + sample.offset = offset; + + (void)send(session->chronyfd, &sample, sizeof (sample), 0); +} + +static void wrap_hook(struct gps_device_t *session) +{ + if (session->chronyfd != -1) + (void)close(session->chronyfd); +} + +static /*@observer@*/ char *report_hook(struct gps_device_t *session, + struct timeval *actual_tv, + struct timespec *ts, + double edge_offset) +/* ship the time of a PPS event to ntpd and/or chrony */ +{ + char *log1; + + if (!session->ship_to_ntpd) + return "skipped ship_to_ntp=0"; + + /* + * Only listen to PPS after several consecutive fixes, + * otherwise time may be inaccurate. (We know this is + * required on some Garmins in binary mode; safest to do it + * for all case we're talking to a Garmin in text mode, and + * out of general safety-first conservatism.) + * + * Not sure yet how to handle uBlox UBX_MODE_TMONLY + */ + if (session->fixcnt <= PPS_MIN_FIXES) + return "no fix"; + + log1 = "accepted"; + if ( 0 <= session->chronyfd ) { + log1 = "accepted chrony sock"; + chrony_send(session, actual_tv, ts, edge_offset); + } + (void)ntpshm_pps(session, actual_tv, ts); + + return log1; +} + +static void error_hook(struct gps_device_t *session) +{ + (void)ntpshm_free(session->context, session->shmTimeP); +} +#endif /* PPS_ENABLE */ + +void ntpd_link_deactivate(struct gps_device_t *session) +/* release ntpshm storage for a session */ +{ + (void)ntpshm_free(session->context, session->shmindex); +#if defined(PPS_ENABLE) + if (session->shmTimeP != -1) { + pps_thread_deactivate(session); + (void)ntpshm_free(session->context, session->shmTimeP); + } +#endif /* PPS_ENABLE */ +} + +void ntpd_link_activate(struct gps_device_t *session) +/* set up ntpshm storage for a session */ +{ + /* If we are talking to ntpd, allocate a shared-memory segment for "NMEA" time data */ + if (session->context->enable_ntpshm) + session->shmindex = ntpshm_alloc(session->context); + + if (0 > session->shmindex) { + gpsd_report(session->context->debug, LOG_INF, "NTPD ntpshm_alloc() failed\n"); +#if defined(PPS_ENABLE) + } else { + /* We also have the 1pps capability, allocate a shared-memory segment + * for the 1pps time data and launch a thread to capture the 1pps + * transitions + */ + if ((session->shmTimeP = ntpshm_alloc(session->context)) < 0) { + gpsd_report(session->context->debug, LOG_INF, "NTPD ntpshm_alloc(1) failed\n"); + } else { + session->thread_init_hook = init_hook; + session->thread_error_hook = error_hook; + session->thread_report_hook = report_hook; + session->thread_wrap_hook = wrap_hook; + pps_thread_activate(session); + } +#endif /* PPS_ENABLE */ + } +} + +#endif /* NTPSHM_ENABLE */ +/* end */ diff --git a/subframe.c b/subframe.c index d776b59f..25097428 100644 --- a/subframe.c +++ b/subframe.c @@ -728,7 +728,7 @@ gps_mask_t gpsd_interpret_subframe(struct gps_device_t *session, subp->sub4_18.leap, subp->sub4_18.WNlsf, subp->sub4_18.DN, subp->sub4_18.lsf); -#ifdef TIMESERVICE_ENABLE +#ifdef NTPSHM_ENABLE /* IS-GPS-200 Revision E, paragraph 20.3.3.5.2.4 */ if (((session->context->gps_week % 256) == (unsigned short)subp->sub4_18.WNlsf) && /* notify the leap seconds correction in the end of current day */ @@ -742,7 +742,7 @@ gps_mask_t gpsd_interpret_subframe(struct gps_device_t *session, session->context->leap_notify = LEAP_NOWARNING; } else session->context->leap_notify = LEAP_NOWARNING; -#endif /* TIMESERVICE_ENABLE */ +#endif /* NTPSHM_ENABLE */ session->context->leap_seconds = (int)subp->sub4_18.leap; session->context->valid |= LEAP_SECOND_VALID; diff --git a/timeexport.c b/timeexport.c deleted file mode 100644 index c2067860..00000000 --- a/timeexport.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * timeexport.c - put time information in SHM segment for xntpd, or to chrony - * - * struct shmTime and getShmTime from file in the xntp distribution: - * sht.c - Testprogram for shared memory refclock - * - * This file is Copyright (c) 2010 by the GPSD project BSD terms apply: - * see the file COPYING in the distribution root for details. - */ - -#include -#include -#include -#include -#include -#include -#include -#ifndef S_SPLINT_S -#include -#include -#include -#endif /* S_SPLINT_S */ - -#include "gpsd.h" - -#ifdef TIMESERVICE_ENABLE -#include -#include -#include - -#define NTPD_BASE 0x4e545030 /* "NTP0" */ -#define SHM_UNIT 0 /* SHM driver unit number (0..3) */ - -#define PPS_MIN_FIXES 3 /* # fixes to wait for before shipping PPS */ - -struct shmTime -{ - int mode; /* 0 - if valid set - * use values, - * clear valid - * 1 - if valid set - * if count before and after read of values is equal, - * use values - * clear valid - */ - int count; - time_t clockTimeStampSec; - int clockTimeStampUSec; - time_t receiveTimeStampSec; - int receiveTimeStampUSec; - int leap; - int precision; - int nsamples; - int valid; - int pad[10]; -}; - -/* Note: you can start gpsd as non-root, and have it work with ntpd. - * However, it will then only use the ntpshm segments 2 and 3. - * - * Ntpd always runs as root (to be able to control the system clock). - * Its logics for the creation of ntpshm segments are: - * - * Segments 0 and 1: permissions 0600, i.e. other programs can only - * read and write as root. - * - * Segments 2 and 3: permissions 0666, i.e. other programs can read - * and write as any user. I.e.: if ntpd has been - * configured to use these segments, any - * unpriviliged user is allowed to provide data - * for synchronisation. - * * As gpsd can be started as both root and non-root, this behaviour is - * mimicked by: - * - * Started as root: do as ntpd when attaching (creating) the segments. - * (In contrast to ntpd, which only attaches (creates) configured - * segments, gpsd creates all segments.) - * - * Started as non-root: only attach (create) segments 2 and 3 with - * permissions 0666. As the permissions are for any user, the creator - * does not matter. - * - * For each GPS module gpsd controls, it will use the attached ntpshm - * segments in pairs (for coarse clock and pps source, respectively) - * starting from the first found segments. I.e. started as root, one - * GPS will deliver data on segments 0 and 1, and as non-root data - * will be delivered on segments 2 and 3. - * - * to debug, try looking at the live segments this way - * - * ipcs -m - * - * results should look like this: - * ------ Shared Memory Segments -------- - * key shmid owner perms bytes nattch status - * 0x4e545030 0 root 700 96 2 - * 0x4e545031 32769 root 700 96 2 - * 0x4e545032 163842 root 666 96 1 - * 0x4e545033 196611 root 666 96 1 - * - * For a bit more data try this: - * cat /proc/sysvipc/shm - * - * If gpsd can not open the segments be sure you are not running SELinux - * or apparmor. - * - * if you see the shared segments (keys 1314148400 -- 1314148403), and - * no gpsd or ntpd is running then try removing them like this: - * - * ipcrm -M 0x4e545030 - * ipcrm -M 0x4e545031 - * ipcrm -M 0x4e545032 - * ipcrm -M 0x4e545033 - */ -static /*@null@*/ volatile struct shmTime *getShmTime(struct gps_context_t *context, int unit) -{ - int shmid; - unsigned int perms; - volatile struct shmTime *p; - // set the SHM perms the way ntpd does - if (unit < 2) { - // we are root, be careful - perms = 0600; - } else { - // we are not root, try to work anyway - perms = 0666; - } - - /* - * Note: this call requires root under BSD, and possibly on - * well-secured Linux systems. This is why ntpshm_init() has to be - * called before privilege-dropping. - */ - shmid = shmget((key_t) (NTPD_BASE + unit), - sizeof(struct shmTime), (int)(IPC_CREAT | perms)); - if (shmid == -1) { - gpsd_report(context->debug, LOG_ERROR, - "NTPD shmget(%ld, %zd, %o) fail: %s\n", - (long int)(NTPD_BASE + unit), sizeof(struct shmTime), - (int)perms, strerror(errno)); - return NULL; - } - p = (struct shmTime *)shmat(shmid, 0, 0); - /*@ -mustfreefresh */ - if ((int)(long)p == -1) { - gpsd_report(context->debug, LOG_ERROR, - "NTPD shmat failed: %s\n", - strerror(errno)); - return NULL; - } - gpsd_report(context->debug, LOG_PROG, - "NTPD shmat(%d,0,0) succeeded, segment %d\n", - shmid, unit); - return p; - /*@ +mustfreefresh */ -} - -void ntpshm_init(struct gps_context_t *context) -/* Attach all NTP SHM segments. Called once at startup, while still root. */ -{ - int i; - - for (i = 0; i < NTPSHMSEGS; i++) { - // Only grab the first two when running as root. - if (2 <= i || 0 == getuid()) { - context->shmTime[i] = getShmTime(context, i); - } - } - memset(context->shmTimeInuse, 0, sizeof(context->shmTimeInuse)); - context->enable_ntpshm = true; -} - -static int ntpshm_alloc(struct gps_context_t *context) -/* allocate NTP SHM segment. return its segment number, or -1 */ -{ - int i; - - for (i = 0; i < NTPSHMSEGS; i++) - if (context->shmTime[i] != NULL && !context->shmTimeInuse[i]) { - context->shmTimeInuse[i] = true; - - /* - * In case this segment gets sent to ntpd before an - * ephemeris is available, the LEAP_NOTINSYNC value will - * tell ntpd that this source is in a "clock alarm" state - * and should be ignored. The goal is to prevent ntpd - * from declaring the GPS a falseticker before it gets - * all its marbles together. - */ - memset((void *)context->shmTime[i], 0, sizeof(struct shmTime)); - context->shmTime[i]->mode = 1; - context->shmTime[i]->leap = LEAP_NOTINSYNC; - context->shmTime[i]->precision = -1; /* initially 0.5 sec */ - context->shmTime[i]->nsamples = 3; /* stages of median filter */ - - return i; - } - - return -1; -} - -static bool ntpshm_free(struct gps_context_t * context, int segment) -/* free NTP SHM segment */ -{ - if (segment < 0 || segment >= NTPSHMSEGS) - return false; - - context->shmTimeInuse[segment] = false; - return true; -} - -int ntpshm_put(struct gps_device_t *session, double fixtime, double fudge) -/* put a received fix time into shared memory for NTP */ -{ - /* shmTime is volatile to try to prevent C compiler from reordering - * writes, or optimizing some 'dead code'. but CPU cache may still - *write out of order since we do not use memory barriers, yet */ - volatile struct shmTime *shmTime = NULL; - struct timeval tv; - double seconds, microseconds; - - // gpsd_report(session->context->debug, LOG_PROG, "NTP: doing ntpshm_put(,%g, %g)\n", fixtime, fudge); - if (session->shmindex < 0 || - (shmTime = session->context->shmTime[session->shmindex]) == NULL) { - gpsd_report(session->context->debug, LOG_RAW, - "NTPD missing shm\n"); - return 0; - } - - (void)gettimeofday(&tv, NULL); - fixtime += fudge; - microseconds = 1000000.0 * modf(fixtime, &seconds); - if (shmTime->clockTimeStampSec == (time_t) seconds) { - gpsd_report(session->context->debug, LOG_RAW, - "NTPD ntpshm_put: skipping duplicate second\n"); - return 0; - } - - /* we use the shmTime mode 1 protocol - * - * ntpd does this: - * - * reads valid. - * IFF valid is 1 - * reads count - * reads values - * reads count - * IFF count unchanged - * use values - * clear valid - * - */ - shmTime->valid = 0; - shmTime->count++; - /* FIXME need a memory barrier here to prevent write reordering by - * the compiler or CPU cache */ - shmTime->clockTimeStampSec = (time_t) seconds; - shmTime->clockTimeStampUSec = (int)microseconds; - shmTime->receiveTimeStampSec = (time_t) tv.tv_sec; - shmTime->receiveTimeStampUSec = (int)tv.tv_usec; - shmTime->leap = session->context->leap_notify; - /* setting the precision here does not seem to help anything, too - * hard to calculate properly anyway. Let ntpd figure it out. - * Any NMEA will be about -1 or -2. - * Garmin GPS-18/USB is around -6 or -7. - */ - /* FIXME need a memory barrier here to prevent write reordering by - * the compiler or CPU cache */ - shmTime->count++; - shmTime->valid = 1; - - gpsd_report(session->context->debug, LOG_RAW, - "NTPD ntpshm_put: Clock: %lu.%06lu @ %lu.%06lu, fudge: %0.3f\n", - (unsigned long)seconds, (unsigned long)microseconds, - (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec, fudge); - - return 1; -} - -#ifdef PPS_ENABLE -/*@unused@*//* splint is confused here */ -/* put NTP shared memory info based on received PPS pulse - * - * good news is that kernel PPS gives us nSec resolution - * bad news is that ntpshm only has uSec resolution - * - * actual_tv is the actual time we think the PPS happened - * ts is the time we saw the pulse - */ -static int ntpshm_pps(struct gps_device_t *session, struct timeval *actual_tv, - struct timespec *ts) -{ - volatile struct shmTime *shmTime = NULL, *shmTimeP = NULL; - struct timeval tv; - int precision; - double offset; - - if (0 > session->shmindex || 0 > session->shmTimeP || - (shmTime = session->context->shmTime[session->shmindex]) == NULL || - (shmTimeP = session->context->shmTime[session->shmTimeP]) == NULL) - return 0; - - /* for now we use uSec, not nSec */ - /*@-type@*//* splint is confused about struct timespec */ - TSTOTV( &tv, ts ); - /*@+type@*/ - - /* we use the shmTime mode 1 protocol - * - * ntpd does this: - * - * reads valid. - * IFF valid is 1 - * reads count - * reads values - * reads count - * IFF count unchanged - * use values - * clear valid - * - */ - shmTimeP->valid = 0; - shmTimeP->count++; - shmTimeP->clockTimeStampSec = (time_t)actual_tv->tv_sec; - shmTimeP->clockTimeStampUSec = (int)actual_tv->tv_usec; - shmTimeP->receiveTimeStampSec = (time_t)tv.tv_sec; - shmTimeP->receiveTimeStampUSec = (int)tv.tv_usec; - shmTimeP->leap = session->context->leap_notify; - /* precision is a placebo, ntpd does not really use it - * real world accuracy is around 16uS, thus -16 precision */ - shmTimeP->precision = -16; - shmTimeP->count++; - shmTimeP->valid = 1; - - /* this is more an offset jitter/dispersion than precision, - * but still useful for debug */ - offset = fabs((double)(tv.tv_sec - actual_tv->tv_sec) - + ((double)(tv.tv_usec - actual_tv->tv_usec) / 1000000.0)); - precision = offset != 0 ? (int)(ceil(log(offset) / M_LN2)) : -20; - /*@-type@*//* splint is confused about struct timespec */ - gpsd_report(session->context->debug, LOG_RAW, - "PPS ntpshm_pps %lu.%03lu @ %lu.%09lu, preci %d\n", - (unsigned long)actual_tv->tv_sec, - (unsigned long)actual_tv->tv_usec, - (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec, - precision); - /*@+type@*/ - return 1; -} - -#define SOCK_MAGIC 0x534f434b -struct sock_sample { - struct timeval tv; - double offset; - int pulse; - int leap; - /* cppcheck-suppress unusedStructMember */ - int _pad; - int magic; /* must be SOCK_MAGIC */ -}; - -/*@-mustfreefresh@*/ -static void init_hook(struct gps_device_t *session) -/* for chrony SOCK interface, which allows nSec timekeeping */ -{ -#ifdef CHRONY_ENABLE - /* open the chrony socket */ - char chrony_path[PATH_MAX]; - - session->chronyfd = -1; - if ( 0 == getuid() ) { - /* this case will fire on command-line devices; - * they're opened before priv-dropping. Matters because - * only root can use /var/run. - */ - (void)snprintf(chrony_path, sizeof (chrony_path), - "/var/run/chrony.%s.sock", basename(session->gpsdata.dev.path)); - } else { - (void)snprintf(chrony_path, sizeof (chrony_path), - "/tmp/chrony.%s.sock", basename(session->gpsdata.dev.path)); - } - - if (access(chrony_path, F_OK) != 0) { - gpsd_report(session->context->debug, LOG_PROG, - "PPS chrony socket %s doesn't exist\n", chrony_path); - } else { - session->chronyfd = netlib_localsocket(chrony_path, SOCK_DGRAM); - if (session->chronyfd < 0) - gpsd_report(session->context->debug, LOG_PROG, - "PPS connect chrony socket failed: %s, error: %d, errno: %d/%s\n", - chrony_path, session->chronyfd, errno, strerror(errno)); - else - gpsd_report(session->context->debug, LOG_RAW, - "PPS using chrony socket: %s\n", chrony_path); - } -#endif /* CHRONY_ENABLE */ -} -/*@+mustfreefresh@*/ - - -/* actual_tv is when we think the PPS pulse wass */ -/* ts is the local clocke time we saw the pulse */ -/* offset is actual_tv - tv */ -static void chrony_send(struct gps_device_t *session, - struct timeval *actual_tv, - struct timespec *ts UNUSED, double offset) -{ - struct sock_sample sample; - - /* FIXME!! offset is double of the error from local time */ - /* chrony expects tv-sec since Jan 1970 */ - sample.pulse = 0; - sample.leap = session->context->leap_notify; - sample.magic = SOCK_MAGIC; - sample.tv = *actual_tv; /* structure copy */ - sample.offset = offset; - - (void)send(session->chronyfd, &sample, sizeof (sample), 0); -} - -static void wrap_hook(struct gps_device_t *session) -{ - if (session->chronyfd != -1) - (void)close(session->chronyfd); -} - -static /*@observer@*/ char *report_hook(struct gps_device_t *session, - struct timeval *actual_tv, - struct timespec *ts, - double edge_offset) -/* ship the time of a PPS event to ntpd and/or chrony */ -{ - char *log1; - - if (!session->ship_to_ntpd) - return "skipped ship_to_ntp=0"; - - /* - * Only listen to PPS after several consecutive fixes, - * otherwise time may be inaccurate. (We know this is - * required on some Garmins in binary mode; safest to do it - * for all case we're talking to a Garmin in text mode, and - * out of general safety-first conservatism.) - * - * Not sure yet how to handle uBlox UBX_MODE_TMONLY - */ - if (session->fixcnt <= PPS_MIN_FIXES) - return "no fix"; - - log1 = "accepted"; - if ( 0 <= session->chronyfd ) { - log1 = "accepted chrony sock"; - chrony_send(session, actual_tv, ts, edge_offset); - } - (void)ntpshm_pps(session, actual_tv, ts); - - return log1; -} - -static void error_hook(struct gps_device_t *session) -{ - (void)ntpshm_free(session->context, session->shmTimeP); -} -#endif /* PPS_ENABLE */ - -void ntpd_link_deactivate(struct gps_device_t *session) -/* release ntpshm storage for a session */ -{ - (void)ntpshm_free(session->context, session->shmindex); -#if defined(PPS_ENABLE) - if (session->shmTimeP != -1) { - pps_thread_deactivate(session); - (void)ntpshm_free(session->context, session->shmTimeP); - } -#endif /* PPS_ENABLE */ -} - -void ntpd_link_activate(struct gps_device_t *session) -/* set up ntpshm storage for a session */ -{ - /* If we are talking to ntpd, allocate a shared-memory segment for "NMEA" time data */ - if (session->context->enable_ntpshm) - session->shmindex = ntpshm_alloc(session->context); - - if (0 > session->shmindex) { - gpsd_report(session->context->debug, LOG_INF, "NTPD ntpshm_alloc() failed\n"); -#if defined(PPS_ENABLE) - } else { - /* We also have the 1pps capability, allocate a shared-memory segment - * for the 1pps time data and launch a thread to capture the 1pps - * transitions - */ - if ((session->shmTimeP = ntpshm_alloc(session->context)) < 0) { - gpsd_report(session->context->debug, LOG_INF, "NTPD ntpshm_alloc(1) failed\n"); - } else { - session->thread_init_hook = init_hook; - session->thread_error_hook = error_hook; - session->thread_report_hook = report_hook; - session->thread_wrap_hook = wrap_hook; - pps_thread_activate(session); - } -#endif /* PPS_ENABLE */ - } -} - -#endif /* TIMESERVICE_ENABLE */ -/* end */ diff --git a/www/writing-a-driver.xml b/www/writing-a-driver.xml index 1145fcfa..ab624354 100644 --- a/www/writing-a-driver.xml +++ b/www/writing-a-driver.xml @@ -14,14 +14,6 @@ - - 1.12 - 30 Oct 2013 - er - - Updated by esr; ntp_offset becomes time_offset - - 1.11 19 Jan 2011 @@ -753,12 +745,11 @@ possible, assemble your packet in gpsmon to display the control messages it sends for you. -.timr_offset points to code to -compute an offset to be added, additionally to that in -ntp.conf (if any) when shipping time -notifications to NTP, or the equivalent configuration file for -chrony. If multiple sentences set TIME_IS, this will differ by -sentence type; it should differ by baud rate, as well. +.ntp_offset points to code to compute +an offset to be added, additionally to that in +ntp.conf (if any) when shipping time notifications +to NTP. If multiple sentences set TIME_IS, this will differ by +sentence type; it should differ by baud rare, as well. -- cgit v1.2.1