From d9b8758935f902fb0ea77fee09e9627e09462a11 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Wed, 30 Oct 2013 12:32:12 -0400 Subject: Separate ntpd support from chrony support, step 1. ntp_offset becomes time_offset. There is a new config symbol CHRONY_ENABLE; most time service code is npw controlled by TIMESERVICE_ENABLE. The file ntpshm.c becomes timeexport.c This change is not complete. More disentanglement has to be done inside timeexport.c itself; at the moment enabling one but not both of ntpshm or chrony will probably break its compile. The point of getting this commit out is so Gary will see the new baseline code ASAP. All regression tests pass. --- 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, 700 insertions(+), 676 deletions(-) delete mode 100644 ntpshm.c create mode 100644 timeexport.c diff --git a/SConstruct b/SConstruct index b63c000a..71fc4a62 100644 --- a/SConstruct +++ b/SConstruct @@ -123,6 +123,7 @@ 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"), @@ -575,8 +576,7 @@ else: bluezlibs = [] env["bluez"] = False -# ntpshm is required for pps support -if env['pps'] and env['ntpshm'] and config.CheckHeader("sys/timepps.h"): +if env['pps'] 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','ntpshm.c','shmexport.c','dbusexport.c'] +gpsd_sources = ['gpsd.c','timeexport.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 50b4823f..a73317bf 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(EVERMORE_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_garmin.c b/driver_garmin.c index 32015573..e51beda0 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 NTPSHM_ENABLE -static double garmin_ntp_offset(struct gps_device_t *session) +#ifdef TIMESERVICE_ENABLE +static double garmin_time_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_ntp_offset(struct gps_device_t *session) } return 0.430; /* WTF? WAG */ } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE - .ntp_offset = garmin_ntp_offset, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = garmin_time_offset, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = garmin_ntp_offset, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = garmin_time_offset, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = garmin_ntp_offset, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = garmin_time_offset, +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_geostar.c b/driver_geostar.c index d819e4ad..fd264d5f 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 NTPSHM_ENABLE -static double geostar_ntp_offset(struct gps_device_t *session UNUSED) +#ifdef TIMESERVICE_ENABLE +static double geostar_time_offset(struct gps_device_t *session UNUSED) { return 0.31; } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE - .ntp_offset = geostar_ntp_offset, -#endif /* NTPSHM_ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = geostar_time_offset, +#endif /* TIMESERVICE_ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_italk.c b/driver_italk.c index 2521351f..359614bb 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(ITRAX_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_navcom.c b/driver_navcom.c index 5c6fbd24..f04ce80a 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_nmea2000.c b/driver_nmea2000.c index 68a942ae..562f37dd 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_oncore.c b/driver_oncore.c index 0152933a..0179b53f 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 NTPSHM_ENABLE -static double oncore_ntp_offset(struct gps_device_t *session UNUSED) +#ifdef TIMESERVICE_ENABLE +static double oncore_time_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_ntp_offset(struct gps_device_t *session UNUSED) */ return 0.175; } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE - .ntp_offset = oncore_ntp_offset, /* NTP offset array */ -#endif /* NTPSHM_ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = oncore_time_offset, /* NTP offset array */ +#endif /* TIMESERVICE_ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(ONCORE_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_proto.c b/driver_proto.c index f9f7f060..f14e0e75 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 NTPSHM_ENABLE -static double _proto_ntp_offset(struct gps_device_t *session) +#ifdef TIMESERVICE_ENABLE +static double _proto_time_offset(struct gps_device_t *session) { /* * If NTP notification is enabled, the GPS will occasionally NTP @@ -468,7 +468,7 @@ static double _proto_ntp_offset(struct gps_device_t *session) */ return MAGIC_CONSTANT; } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE - .ntp_offset = _proto_ntp_offset, -#endif /* NTPSHM_ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = _proto_time_offset, +#endif /* TIMESERVICE_ENABLE */ /* *INDENT-ON* */ }; #endif /* defined(_PROTO__ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_sirf.c b/driver_sirf.c index 48902343..275bbc31 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 NTPSHM_ENABLE +#ifdef TIMESERVICE_ENABLE session->driver.sirf.time_seen = 0; -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE +#ifdef TIMESERVICE_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 /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_ENABLE */ gpsd_report(session->context->debug, LOG_DATA, "SiRF: MTD 0x04: visible=%d mask={SATELLITE}\n", session->gpsdata.satellites_visible); return SATELLITE_SET; } -#ifdef NTPSHM_ENABLE -static double sirf_ntp_offset(struct gps_device_t *session) +#ifdef TIMESERVICE_ENABLE +static double sirf_time_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_ntp_offset(struct gps_device_t *session) return retval; } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE +#ifdef TIMESERVICE_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 /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE +#ifdef TIMESERVICE_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 /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE +#ifdef TIMESERVICE_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 /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE +#ifdef TIMESERVICE_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 /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE - .ntp_offset = sirf_ntp_offset, +#ifdef TIMESERVICE_ENABLE + .time_offset = sirf_time_offset, #endif /* NTP_SHM_ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_superstar2.c b/driver_superstar2.c index 31a8658c..d98fa697 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_tsip.c b/driver_tsip.c index 087dfccf..ddc79395 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 NTPSHM_ENABLE -static double tsip_ntp_offset(struct gps_device_t *session UNUSED) +#ifdef TIMESERVICE_ENABLE +static double tsip_time_offset(struct gps_device_t *session UNUSED) { /* FIX-ME: is a constant offset right here? */ return 0.075; } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE - .ntp_offset = tsip_ntp_offset, -#endif /* NTPSHM_ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = tsip_time_offset, +#endif /* TIMESERVICE_ENABLE */ }; /* *INDENT-ON* */ diff --git a/driver_ubx.c b/driver_ubx.c index d1bda91d..a8f414c1 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ #endif /* defined(UBX_ENABLE) && defined(BINARY_ENABLE) */ diff --git a/driver_zodiac.c b/driver_zodiac.c index 296dbece..5ab969a1 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 NTPSHM_ENABLE -static double zodiac_ntp_offset(struct gps_device_t *session UNUSED) +#ifdef TIMESERVICE_ENABLE +static double zodiac_time_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_ntp_offset(struct gps_device_t *session UNUSED) * with the 1pps signal active is required. */ return 1.1; } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 NTPSHM_ENABLE - .ntp_offset = zodiac_ntp_offset, /* compute NTO fudge factor */ -#endif /* NTPSHM_ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = zodiac_time_offset, /* compute NTO fudge factor */ +#endif /* TIMESERVICE_ENABLE */ }; /* *INDENT-ON* */ diff --git a/drivers.c b/drivers.c index e55d8790..52d130bf 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no NTP communication */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no NTP communication */ +#endif /* ENABLE 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 NTPSHM_ENABLE - .ntp_offset = NULL, /* no method for NTP fudge factor */ -#endif /* NTPSHM_ ENABLE */ +#ifdef TIMESERVICE_ENABLE + .time_offset = NULL, /* no method for NTP fudge factor */ +#endif /* ENABLE ENABLE */ }; /* *INDENT-ON* */ diff --git a/gpscap.ini b/gpscap.ini index 533150e4..8c2bc308 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 -# ntp_offset = NTP offset +# time_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 -ntp_offset = 0.125s +time_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 -ntp_offset = ? +time_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 -ntp_offset = ? +time_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 -ntp_offset = ? +time_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 -ntp_offset = ? +time_offset = ? rating = good discontinued = True submitter = Wojciech Kazubski @@ -1612,7 +1612,7 @@ interfaces = USB tested = 3.9 pps = True pps_accuracy = 1ms -ntp_offset = ? +time_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 -ntp_offset = 0.675s +time_offset = 0.675s usbchip = CP2102 tested = regression rating = good @@ -2332,7 +2332,7 @@ interfaces = USB,UART tested = regression pps = True pps_accuracy = 50ns -ntp_offset = ? +time_offset = ? submitter = Chris Kuethe [EVK-5H-0] @@ -2355,7 +2355,7 @@ date = 2011-02-02 interfaces = TTL pps = True pps_accuracy = 50ns -ntp_offset = ? +time_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 -ntp_offset = ? +time_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 b00f46c7..423cea17 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 = ntp_offset = "" + pps_accuracy = time_offset = "" if self.has_option(dev, "pps_accuracy"): pps_accuracy = self.get(dev, "pps_accuracy") - 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)) + 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)) else: ofp.write("?
\n") else: diff --git a/gpsd.c b/gpsd.c index f31d07eb..8c1e1bf1 100644 --- a/gpsd.c +++ b/gpsd.c @@ -223,6 +223,9 @@ 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 @@ -663,9 +666,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 NTPSHM_ENABLE +#ifdef TIMESERVICE_ENABLE ntpd_link_deactivate(device); -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_ENABLE */ gpsd_deactivate(device); } } @@ -717,7 +720,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 NTPSHM_ENABLE +#ifdef TIMESERVICE_ENABLE /* * Now is the right time to grab the shared memory segment(s) * to communicate the navigation message derived and (possibly) @@ -732,7 +735,7 @@ bool gpsd_add_device(const char *device_name, bool flag_nowait) "NTPD ntpd_link_activate: %d\n", (int)devp->shmindex >= 0); -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_ENABLE */ gpsd_report(context.debug, LOG_INF, "stashing device %s at slot %d\n", device_name, (int)(devp - devices)); @@ -1508,7 +1511,7 @@ static void all_reports(struct gps_device_t *device, gps_mask_t changed) } -#ifdef NTPSHM_ENABLE +#ifdef TIMESERVICE_ENABLE /* * Time is eligible for shipping to NTPD if the driver has * asserted PPSTIME_IS at any point in the current cycle. @@ -1536,14 +1539,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->ntp_offset == NULL) + || device->device_type->time_offset == NULL) offset = 0.0; else - offset = device->device_type->ntp_offset(device); + offset = device->device_type->time_offset(device); (void)ntpshm_put(device, device->newdata.time, offset); device->last_fixtime = device->newdata.time; } -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_ENABLE */ /* * If no reliable end of cycle, must report every time @@ -1946,7 +1949,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 NTPSHM_ENABLE +#ifdef TIMESERVICE_ENABLE if (getuid() == 0) { errno = 0; // nice() can ONLY succeed when run as root! @@ -1960,7 +1963,7 @@ int main(int argc, char *argv[]) * to use segments 0 and 1. */ (void)ntpshm_init(&context); -#endif /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_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 a11bcac3..2ff8b5e8 100644 --- a/gpsd.h-tail +++ b/gpsd.h-tail @@ -36,6 +36,10 @@ #include #endif +#if defined(ENABLE_NTPSHM) || defined(ENABLE_CHRONY) +#define TIMESERVICE_ENABLE +#endif + #ifdef _WIN32 typedef unsigned int speed_t; #endif @@ -239,12 +243,14 @@ 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 NTPSHM_ENABLE +#ifdef TIMESERVICE_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 */ @@ -348,9 +354,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 NTPSHM_ENABLE - /*@null@*/double (*ntp_offset)(struct gps_device_t *session); -#endif /* NTPSHM_ENABLE */ +#ifdef TIMESERVICE_ENABLE + /*@null@*/double (*time_offset)(struct gps_device_t *session); +#endif /* TIMESERVICE_ENABLE */ }; /* @@ -471,7 +477,6 @@ 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 *, @@ -480,6 +485,9 @@ 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 aa4f4b7a..c30b3dcf 100644 --- a/libgpsd_core.c +++ b/libgpsd_core.c @@ -231,15 +231,17 @@ void gps_context_init(struct gps_context_t *context) .gps_tow = 0, .century = 0, .rollovers = 0, -#ifdef NTPSHM_ENABLE +#ifdef TIMESERVICE_ENABLE .leap_notify = LEAP_NOWARNING, +#endif /* TIMESERVICE_ENABLE */ +#ifdef NTPSHM_ENABLE .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 deleted file mode 100644 index 5fe96af3..00000000 --- a/ntpshm.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * 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 25097428..d776b59f 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 NTPSHM_ENABLE +#ifdef TIMESERVICE_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 /* NTPSHM_ENABLE */ +#endif /* TIMESERVICE_ENABLE */ session->context->leap_seconds = (int)subp->sub4_18.leap; session->context->valid |= LEAP_SECOND_VALID; diff --git a/timeexport.c b/timeexport.c new file mode 100644 index 00000000..c2067860 --- /dev/null +++ b/timeexport.c @@ -0,0 +1,507 @@ +/* + * 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 ab624354..1145fcfa 100644 --- a/www/writing-a-driver.xml +++ b/www/writing-a-driver.xml @@ -14,6 +14,14 @@ + + 1.12 + 30 Oct 2013 + er + + Updated by esr; ntp_offset becomes time_offset + + 1.11 19 Jan 2011 @@ -745,11 +753,12 @@ possible, assemble your packet in gpsmon to display the control messages it sends for you. -.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. +.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. -- cgit v1.2.1