From a3eae28631c9bb93912c519030cb3c16a1e11969 Mon Sep 17 00:00:00 2001 From: Pascal Martin Date: Sun, 10 Nov 2019 22:53:32 -0800 Subject: [PATCH] Fix the help texts and the NTP server module --- hc_broadcast.c | 27 +++++++----- hc_broadcast.h | 6 ++- hc_clock.c | 30 ++++++++++--- hc_clock.h | 1 + hc_http.c | 17 +++++--- hc_http.h | 2 + hc_nmea.c | 8 ++-- hc_ntp.c | 115 ++++++++++++++++++++++++++++++++++++------------- houseclock.c | 12 +++++- 9 files changed, 157 insertions(+), 61 deletions(-) diff --git a/hc_broadcast.c b/hc_broadcast.c index 43c0b1c..70b5045 100644 --- a/hc_broadcast.c +++ b/hc_broadcast.c @@ -145,31 +145,38 @@ void hc_broadcast_send (const char *data, int length) { } +const char *hc_broadcast_format (struct sockaddr_in *addr) { + static char formatted[80]; + snprintf (formatted, sizeof(formatted), "%d.%d.%d.%d:%d", + addr->sin_addr.s_addr & 0xff, + (addr->sin_addr.s_addr >> 8) & 0xff, + (addr->sin_addr.s_addr >> 16) & 0xff, + (addr->sin_addr.s_addr >> 24) & 0xff, + addr->sin_port); + return formatted; +} + void hc_broadcast_reply - (const char *data, int length, in_addr_t destination) { + (const char *data, int length, struct sockaddr_in *destination) { if (udpserver < 0) return; - netaddress.sin_addr.s_addr = destination; sendto (udpserver, data, length, 0, - (struct sockaddr *)&netaddress, sizeof(netaddress)); + (struct sockaddr *)destination, sizeof(struct sockaddr_in)); } -int hc_broadcast_receive (char *buffer, int size, in_addr_t *source) { +int hc_broadcast_receive (char *buffer, int size, + struct sockaddr_in *source) { int length; - struct sockaddr_in srcaddr; - socklen_t srclength = sizeof(srcaddr); + socklen_t srclength = sizeof(struct sockaddr_in); if (udpserver < 0) return 0; length = recvfrom (udpserver, buffer, size, 0, - (struct sockaddr *)&srcaddr, &srclength); + (struct sockaddr *)source, &srclength); - if (length > 0) { - *source = srcaddr.sin_addr.s_addr; - } return length; } diff --git a/hc_broadcast.h b/hc_broadcast.h index 9e8232a..5a6651f 100644 --- a/hc_broadcast.h +++ b/hc_broadcast.h @@ -31,8 +31,10 @@ int hc_broadcast_open (const char *service); void hc_broadcast_send (const char *data, int length); void hc_broadcast_reply - (const char *data, int length, in_addr_t destination); + (const char *data, int length, struct sockaddr_in *destination); int hc_broadcast_receive - (char *buffer, int size, in_addr_t *source); + (char *buffer, int size, struct sockaddr_in *source); + +const char *hc_broadcast_format (struct sockaddr_in *addr); diff --git a/hc_clock.c b/hc_clock.c index 37622cb..7556017 100644 --- a/hc_clock.c +++ b/hc_clock.c @@ -65,6 +65,7 @@ static int clockPrecision; static int clockShowDrift = 0; static int clockSynchronized = 0; +static struct timeval clockReference = {0, 0}; static hc_clock_status *hc_clock_status_db = 0; static int *hc_clock_drift_db = 0; @@ -122,7 +123,7 @@ void hc_clock_initialize (int argc, const char **argv) { } static void hc_clock_force (const struct timeval *gps, - const struct timeval *local) { + const struct timeval *local, int latency) { struct timeval now; struct timeval corrected = *gps; @@ -133,7 +134,7 @@ static void hc_clock_force (const struct timeval *gps, // current time, as estimated using the local clock. // corrected.tv_sec += (now.tv_sec - local->tv_sec); - corrected.tv_usec += (now.tv_usec - local->tv_usec); + corrected.tv_usec += (now.tv_usec - local->tv_usec) + (latency * 1000); if (corrected.tv_usec > 1000000) { corrected.tv_sec += 1; corrected.tv_usec -= 1000000; @@ -149,6 +150,7 @@ static void hc_clock_force (const struct timeval *gps, if (settimeofday (&corrected, NULL) != 0) { printf ("settimeofday() error %d\n", errno); } + clockReference = now; } static void hc_clock_adjust (time_t drift) { @@ -160,11 +162,14 @@ static void hc_clock_adjust (time_t drift) { if (adjtime (&delta, NULL) != 0) { printf ("adjtime() error %d\n", errno); } + gettimeofday (&clockReference, NULL); } void hc_clock_synchronize(const struct timeval *gps, const struct timeval *local, int latency) { + static int FirstCall = 1; + if (hc_clock_drift_db == 0) return; if (hc_clock_status_db == 0) return; @@ -179,13 +184,21 @@ void hc_clock_synchronize(const struct timeval *gps, if (clockShowDrift || hc_test_mode()) { printf ("[%d] %8.3f\n", local->tv_sec%120, drift/1000.0); - if (hc_test_mode()) return; + if (hc_test_mode()) { + if (absdrift < clockPrecision) { + clockSynchronized = hc_clock_status_db->synchronized = 1; + } else { + clockSynchronized = hc_clock_status_db->synchronized = 0; + } + return; + } } - if (absdrift >= 10000) { + if (FirstCall || absdrift >= 10000) { // Too much of a difference: force system time. - hc_clock_force (gps, local); + hc_clock_force (gps, local, latency); hc_clock_start_learning(); + FirstCall = 0; return; } @@ -205,8 +218,7 @@ void hc_clock_synchronize(const struct timeval *gps, printf ("Average drift: %d ms\n", drift); if (absdrift < clockPrecision) { - clockSynchronized = 1; - hc_clock_status_db->synchronized = 1; + clockSynchronized = hc_clock_status_db->synchronized = 1; } else { // GPS and local system time have drifted apart // by a small difference: adjust the time progressively. @@ -225,3 +237,7 @@ int hc_clock_synchronized (void) { return clockSynchronized; } +void hc_clock_reference (struct timeval *reference) { + *reference = clockReference; +} + diff --git a/hc_clock.h b/hc_clock.h index 1308ebe..b19b563 100644 --- a/hc_clock.h +++ b/hc_clock.h @@ -26,6 +26,7 @@ void hc_clock_initialize (int argc, const char **argv); void hc_clock_synchronize (const struct timeval *gps, const struct timeval *local, int latency); int hc_clock_synchronized (void); +void hc_clock_reference (struct timeval *reference); /* Live database. */ diff --git a/hc_http.c b/hc_http.c index 6149230..d0cf7e6 100644 --- a/hc_http.c +++ b/hc_http.c @@ -64,6 +64,7 @@ static const char *hc_http_status (const char *method, const char *uri, static hc_clock_status *clock_db = 0; char latitude[20]; char longitude[20]; + const char *date = "010100"; if (nmea_db == 0) { nmea_db = (hc_nmea_status *) hc_http_attach (HC_NMEA_STATUS); @@ -102,20 +103,18 @@ static const char *hc_http_status (const char *method, const char *uri, nmea_db->longitude, nmea_db->hemisphere[1]); } + if (nmea_db->date[0] > 0) date = nmea_db->date; + snprintf (JsonBuffer, sizeof(JsonBuffer), "{\"gps\":{\"fix\":%s" - ",\"time\":[%c%c,%c%c,%c%c],\"date\":[%d,%c%c,%c%c]" + ",\"time\":\"%s\",\"date\":\"%4d%2.2s%2.2s\"" ",\"latitude\":%s,\"longitude\":%s}" ",\"clock\":{\"synchronized\":%s" ",\"precision\":%d,\"drift\":%d,\"timestamp\":%zd.%03d}" ",\"learn\":{\"count\":%d,\"accumulator\":%d}}", nmea_db->fix?"true":"false", - nmea_db->time[0], nmea_db->time[1], - nmea_db->time[2], nmea_db->time[3], - nmea_db->time[4], nmea_db->time[5], - 2000 + (nmea_db->date[4]-'0')*10 + (nmea_db->date[5]-'0'), - nmea_db->date[2], nmea_db->date[3], - nmea_db->date[0], nmea_db->date[1], + nmea_db->time, + 2000 + (date[4]-'0')*10 + (date[5]-'0'), date+2, date, latitude, longitude, clock_db->synchronized?"true":"false", clock_db->precision, @@ -160,6 +159,10 @@ static const char *hc_http_clockdrift (const char *method, const char *uri, return JsonBuffer; } +const char *hc_http_help (int level) { + return echttp_help(level); +} + void hc_http (int argc, const char **argv) { parent = getppid(); if (echttp_open (argc, argv) <= 0) exit(1); diff --git a/hc_http.h b/hc_http.h index 0197584..17c190d 100644 --- a/hc_http.h +++ b/hc_http.h @@ -17,5 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ +const char *hc_http_help (int level); + void hc_http (int argc, const char **argv); diff --git a/hc_nmea.c b/hc_nmea.c index 6b91e07..ecee5a3 100644 --- a/hc_nmea.c +++ b/hc_nmea.c @@ -155,10 +155,10 @@ const char *hc_nmea_help (int level) { static const char *nmeaHelp[] = { " [-gps=DEV] [-latency=N] [-burst] [-privacy]", - "-gps=DEV: TTY device from which to read the NMEA data.\n" - "-latency=N: delay between the GPS fix and the 1st NMEA sentence.\n" - "-show-nmea: trace NMEA sentences.\n" - "-burst: Use burst start as the GPS timing reference\n" + "-gps=DEV: TTY device from which to read the NMEA data.", + "-latency=N: delay between the GPS fix and the 1st NMEA sentence.", + "-show-nmea: trace NMEA sentences.", + "-burst: Use burst start as the GPS timing reference", "-privacy: do not export location", NULL }; diff --git a/hc_ntp.c b/hc_ntp.c index aa199c6..5c699b5 100644 --- a/hc_ntp.c +++ b/hc_ntp.c @@ -40,6 +40,7 @@ #include "houseclock.h" #include "hc_ntp.h" +#include "hc_clock.h" #include "hc_broadcast.h" #define NTP_VERSION 3 @@ -80,17 +81,31 @@ typedef struct // The template for all responses (the first fields never change): // ntpHeaderV3 ntpResponse = { - 0x1c, // li=0, vn=3, mode=4. + 0x24, // li=0, vn=4, mode=4. 1, // a GPS-equipped server is stratum 1. 10, // default poll interval recommended in rfc 5905. -10, // don't expect anything better than a millisecond accuracy. 0, 0, "GPS", - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0} + {0, 0}, // reference. + {0, 0}, // origin (same as request) + {0, 0}, // receive. + {0, 0} // transmit. +}; + +ntpHeaderV3 ntpBroadcast = { + 0x25, // li=0, vn=4, mode=5. + 1, // a GPS-equipped server is stratum 1. + 10, // default poll interval recommended in rfc 5905. + -10, // don't expect anything better than a millisecond accuracy. + 0, + 0, + "GPS", + {0, 0}, // Reference. + {0, 0}, // origin (always 0) + {0, 0}, // receive (always 0) + {0, 0} // transmit. }; static const ntpTimestamp zeroTimestamp = {0, 0}; @@ -99,8 +114,8 @@ static const ntpTimestamp zeroTimestamp = {0, 0}; const char *hc_ntp_help (int level) { static const char *ntpHelp[] = { - " [-service=NAME]", - "-service=NAME: name or port for the NTP socket", + " [-ntp-service=NAME]", + "-ntp-service=NAME: name or port for the NTP socket", NULL }; @@ -113,7 +128,7 @@ int hc_ntp_initialize (int argc, const char **argv) { const char *ntpservice = "ntp"; for (i = 1; i < argc; ++i) { - hc_match ("-service=", argv[i], &ntpservice); + hc_match ("-ntp-service=", argv[i], &ntpservice); } if (strcmp(ntpservice, "none") == 0) { return 0; // Do not act as a NTP server. @@ -124,55 +139,97 @@ int hc_ntp_initialize (int argc, const char **argv) { } -void hc_ntp_process (const struct timeval *receive, - int synchronized) { +static void hc_ntp_set_timestamp (ntpTimestamp *ntp, + const struct timeval *local) { + ntp->seconds = htonl((uint32_t) (local->tv_sec) + 2208988800); + ntp->fraction = htonl(NTP_US_TO_FRACTION(local->tv_usec)); +} + +static void hc_ntp_set_reference (ntpHeaderV3 *packet) { + + struct timeval timestamp; + hc_clock_reference (×tamp); + hc_ntp_set_timestamp (&(packet->reference), ×tamp); +} + + +void hc_ntp_process (const struct timeval *receive, int synchronized) { - in_addr_t source; + struct sockaddr_in source; // The receive buffer is as large as the max UDP packet: no overflow ever. char buffer[0x10000]; int length = hc_broadcast_receive(buffer, sizeof(buffer), &source); - if (!synchronized) return; // Ignore all requests until local time is OK. + if (!synchronized) { + if (hc_debug_enabled()) + printf ("Ignoring request from %s: not synchronized\n", + hc_broadcast_format (&source)); + return; // Ignore all requests until local time is OK. + } if (length >= sizeof(ntpHeaderV3)) { struct timeval transmit; ntpHeaderV3 *head = (ntpHeaderV3 *)buffer; int version = (head->liVnMode >> 3) & 0x7; - ntpHeaderV3 response; - - if (version < 3) return; - if (head->liVnMode & 0x7 != 3) return; + switch (head->liVnMode & 0x7) { + case 6: return; // Control. + case 5: return; // Server broadcast. + case 4: return; // Server response. + case 3: break; // request. + default: + if (hc_debug_enabled()) + printf ("Ignore packet from %s: version=%d, liVnMode=%d\n", + hc_broadcast_format (&source), + version, head->liVnMode & 0x7); + return; + } // Now we know this is a client packet with version 3 or above. // Build the response using the system clock, which is assumed to // be synchronized with the GPS clock. - ntpResponse.origin = head->origin; - ntpResponse.receive.seconds = (uint32_t) (receive->tv_sec); - ntpResponse.receive.fraction = NTP_US_TO_FRACTION(receive->tv_usec); + if (hc_debug_enabled()) + printf ("Processing request from %s, transmit=%u/%08x\n", + hc_broadcast_format (&source), + ntohl(head->transmit.seconds), + ntohl(head->transmit.fraction)); + + + ntpResponse.origin = head->transmit; + hc_ntp_set_reference (&ntpResponse); + hc_ntp_set_timestamp (&ntpResponse.receive, receive); gettimeofday (&transmit, NULL); - ntpResponse.transmit.seconds = (uint32_t) (transmit.tv_sec); - ntpResponse.transmit.fraction = NTP_US_TO_FRACTION(transmit.tv_usec); + hc_ntp_set_timestamp (&ntpResponse.transmit, &transmit); hc_broadcast_reply - ((char *)&ntpResponse, sizeof(ntpResponse), source); + ((char *)&ntpResponse, sizeof(ntpResponse), &source); + + if (hc_debug_enabled()) + printf ("Response: origin=%u/%08x, reference=%u/%08x, " + "receive=%u/%08x, transmit=%u/%08x\n", + ntohl(ntpResponse.origin.seconds), + ntohl(ntpResponse.origin.fraction), + ntohl(ntpResponse.reference.seconds), + ntohl(ntpResponse.reference.fraction), + ntohl(ntpResponse.receive.seconds), + ntohl(ntpResponse.receive.fraction), + ntohl(ntpResponse.transmit.seconds), + ntohl(ntpResponse.transmit.fraction)); } } void hc_ntp_periodic (const struct timeval *wakeup) { - struct timeval transmit; + struct timeval timestamp; - ntpResponse.origin = zeroTimestamp; - ntpResponse.receive = zeroTimestamp; + hc_ntp_set_reference (&ntpBroadcast); - gettimeofday (&transmit, NULL); - ntpResponse.transmit.seconds = (uint32_t) (transmit.tv_sec); - ntpResponse.transmit.fraction = NTP_US_TO_FRACTION(transmit.tv_usec); + gettimeofday (×tamp, NULL); + hc_ntp_set_timestamp (&ntpBroadcast.transmit, ×tamp); - hc_broadcast_send ((char *)&ntpResponse, sizeof(ntpResponse)); + hc_broadcast_send ((char *)&ntpBroadcast, sizeof(ntpBroadcast)); } diff --git a/houseclock.c b/houseclock.c index 9e49770..59d7249 100644 --- a/houseclock.c +++ b/houseclock.c @@ -88,7 +88,8 @@ static void hc_help (const char *argv0) { int i = 1; const char *help; - printf ("%s [-h] [-debug] [-test] [-period=N]%s\n", argv0, hc_ntp_help(0)); + printf ("%s [-h] [-debug] [-test] [-period=N]%s%s%s\n", + argv0, hc_ntp_help(0), hc_nmea_help(0), hc_http_help(0)); printf ("\nGeneral options:\n"); printf (" -h: print this help.\n"); @@ -103,11 +104,18 @@ static void hc_help (const char *argv0) { printf (" %s\n", help); help = hc_ntp_help(++i); } - help = hc_ntp_help(i=1); + printf ("\nGPS options:\n"); + help = hc_nmea_help(i=1); while (help) { printf (" %s\n", help); help = hc_nmea_help(++i); } + printf ("\nHTTP options:\n"); + help = hc_http_help(i=1); + while (help) { + printf (" %s\n", help); + help = hc_http_help(++i); + } exit (0); }