diff --git a/candm.h b/candm.h index 9f44808..fd93705 100644 --- a/candm.h +++ b/candm.h @@ -102,6 +102,13 @@ typedef struct { /* This is used in tv_sec_high for 32-bit timestamps */ #define TV_NOHIGHSEC 0x7fffffff +/* 32-bit floating-point format consisting of 7-bit signed exponent + and 25-bit signed coefficient without hidden bit. + The result is calculated as: 2^(exp - 25) * coef */ +typedef struct { + int32_t f; +} Float; + /* The EOR (end of record) fields are used by the offsetof operator in pktlength.c, to get the number of bytes that ought to be transmitted for each packet type. */ @@ -145,18 +152,18 @@ typedef struct { typedef struct { IPAddr address; - int32_t new_max_delay; + Float new_max_delay; int32_t EOR; } REQ_Modify_Maxdelay; typedef struct { IPAddr address; - int32_t new_max_delay_ratio; + Float new_max_delay_ratio; int32_t EOR; } REQ_Modify_Maxdelayratio; typedef struct { - int32_t new_max_update_skew; + Float new_max_update_skew; int32_t EOR; } REQ_Modify_Maxupdateskew; @@ -216,8 +223,8 @@ typedef struct { int32_t maxpoll; int32_t presend_minpoll; uint32_t authkey; - int32_t max_delay; - int32_t max_delay_ratio; + Float max_delay; + Float max_delay_ratio; uint32_t flags; int32_t EOR; } REQ_NTP_Source; @@ -232,7 +239,7 @@ typedef struct { } REQ_WriteRtc; typedef struct { - int32_t dfreq; + Float dfreq; int32_t EOR; } REQ_Dfreq; @@ -325,7 +332,8 @@ typedef struct { Version 3 : NTP_Source message lengthened (auto_offline) Version 4 : IPv6 addressing added, 64-bit time values, sourcestats - and tracking reports extended, added flags to NTP source request + and tracking reports extended, added flags to NTP source request, + replaced fixed-point format with floating-point */ @@ -398,13 +406,6 @@ typedef struct { #define PERMIT_LOCAL 1 #define PERMIT_AUTH 2 -/* ================================================== */ -/* These conversion utilities are used to convert between the internal - and the 'wire' representation of real quantities */ - -#define WIRE2REAL(x) ((double) ((int32_t) ntohl(x)) / 65536.0) -#define REAL2WIRE(x) (htonl((int32_t)(0.5 + 65536.0 * (x)))) - /* ================================================== */ /* Reply codes */ @@ -487,11 +488,11 @@ typedef struct { Timeval ref_time; uint32_t current_correction_s; uint32_t current_correction_us; - int32_t freq_ppm; - int32_t resid_freq_ppm; - int32_t skew_ppm; - int32_t root_delay; - int32_t root_dispersion; + Float freq_ppm; + Float resid_freq_ppm; + Float skew_ppm; + Float root_delay; + Float root_dispersion; int32_t EOR; } RPY_Tracking; @@ -502,8 +503,8 @@ typedef struct { uint32_t n_runs; uint32_t span_seconds; uint32_t sd_us; - int32_t resid_freq_ppm; - int32_t skew_ppm; + Float resid_freq_ppm; + Float skew_ppm; int32_t EOR; } RPY_Sourcestats; @@ -512,15 +513,15 @@ typedef struct { uint16_t n_samples; uint16_t n_runs; uint32_t span_seconds; - int32_t rtc_seconds_fast; - int32_t rtc_gain_rate_ppm; + Float rtc_seconds_fast; + Float rtc_gain_rate_ppm; int32_t EOR; } RPY_Rtc; typedef struct { uint32_t centiseconds; - int32_t dfreq_ppm; - int32_t new_afreq_ppm; + Float dfreq_ppm; + Float new_afreq_ppm; int32_t EOR; } RPY_ManualTimestamp; @@ -562,9 +563,9 @@ typedef struct { typedef struct { Timeval when; - int32_t slewed_offset; - int32_t orig_offset; - int32_t residual; + Float slewed_offset; + Float orig_offset; + Float residual; } RPY_ManualListSample; typedef struct { diff --git a/client.c b/client.c index 1872d12..28ee1f6 100644 --- a/client.c +++ b/client.c @@ -423,7 +423,7 @@ process_cmd_maxdelay(CMD_Request *msg, char *line) if (read_address_double(line, &address, &max_delay)) { UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelay.address); - msg->data.modify_maxdelay.new_max_delay = REAL2WIRE(max_delay); + msg->data.modify_maxdelay.new_max_delay = UTI_FloatHostToNetwork(max_delay); msg->command = htons(REQ_MODIFY_MAXDELAY); ok = 1; } else { @@ -445,7 +445,7 @@ process_cmd_maxdelayratio(CMD_Request *msg, char *line) if (read_address_double(line, &address, &max_delay_ratio)) { UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelayratio.address); - msg->data.modify_maxdelayratio.new_max_delay_ratio = REAL2WIRE(max_delay_ratio); + msg->data.modify_maxdelayratio.new_max_delay_ratio = UTI_FloatHostToNetwork(max_delay_ratio); msg->command = htons(REQ_MODIFY_MAXDELAYRATIO); ok = 1; } else { @@ -465,7 +465,7 @@ process_cmd_maxupdateskew(CMD_Request *msg, char *line) double new_max_update_skew; if (sscanf(line, "%lf", &new_max_update_skew) == 1) { - msg->data.modify_maxupdateskew.new_max_update_skew = REAL2WIRE(new_max_update_skew); + msg->data.modify_maxupdateskew.new_max_update_skew = UTI_FloatHostToNetwork(new_max_update_skew); msg->command = htons(REQ_MODIFY_MAXUPDATESKEW); ok = 1; } else { @@ -845,9 +845,9 @@ process_cmd_dfreq(CMD_Request *msg, char *line) double dfreq; msg->command = htons(REQ_DFREQ); if (sscanf(line, "%lf", &dfreq) == 1) { - msg->data.dfreq.dfreq = REAL2WIRE(dfreq); + msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(dfreq); } else { - msg->data.dfreq.dfreq = REAL2WIRE(0.0); + msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(0.0); } } @@ -908,8 +908,8 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll); msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll); msg->data.ntp_source.authkey = htonl(data.params.authkey); - msg->data.ntp_source.max_delay = REAL2WIRE(data.params.max_delay); - msg->data.ntp_source.max_delay_ratio = REAL2WIRE(data.params.max_delay_ratio); + msg->data.ntp_source.max_delay = UTI_FloatHostToNetwork(data.params.max_delay); + msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio); msg->data.ntp_source.flags = htonl( (data.params.online ? REQ_ADDSRC_ONLINE : 0) | (data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0)); @@ -1682,9 +1682,9 @@ process_cmd_sourcestats(char *line) n_samples = ntohl(reply.data.sourcestats.n_samples); n_runs = ntohl(reply.data.sourcestats.n_runs); span_seconds = ntohl(reply.data.sourcestats.span_seconds); - resid_freq_ppm = WIRE2REAL(reply.data.sourcestats.resid_freq_ppm); - skew_ppm = WIRE2REAL(reply.data.sourcestats.skew_ppm); sd_us = ntohl(reply.data.sourcestats.sd_us); + resid_freq_ppm = UTI_FloatNetworkToHost(reply.data.sourcestats.resid_freq_ppm); + skew_ppm = UTI_FloatNetworkToHost(reply.data.sourcestats.skew_ppm); if (ip_addr.family == IPADDR_UNSPEC) snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_RefidToString(ref_id)); @@ -1760,11 +1760,11 @@ process_cmd_tracking(char *line) correction = (double) correction_tv.tv_sec + 1.0e-6 * correction_tv.tv_usec; printf("System time : %.6f seconds %s of NTP time\n", fabs(correction), (correction > 0.0) ? "slow" : "fast"); - freq_ppm = WIRE2REAL(reply.data.tracking.freq_ppm); - resid_freq_ppm = WIRE2REAL(reply.data.tracking.resid_freq_ppm); - skew_ppm = WIRE2REAL(reply.data.tracking.skew_ppm); - root_delay = WIRE2REAL(reply.data.tracking.root_delay); - root_dispersion = WIRE2REAL(reply.data.tracking.root_dispersion); + freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.freq_ppm); + resid_freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.resid_freq_ppm); + skew_ppm = UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm); + root_delay = UTI_FloatNetworkToHost(reply.data.tracking.root_delay); + root_dispersion = UTI_FloatNetworkToHost(reply.data.tracking.root_dispersion); printf("Frequency : %.3f ppm %s\n", fabs(freq_ppm), (freq_ppm < 0.0) ? "slow" : "fast"); printf("Residual freq : %.3f ppm\n", resid_freq_ppm); printf("Skew : %.3f ppm\n", skew_ppm); @@ -1796,8 +1796,8 @@ process_cmd_rtcreport(char *line) n_samples = ntohs(reply.data.rtc.n_samples); n_runs = ntohs(reply.data.rtc.n_runs); span_seconds = ntohl(reply.data.rtc.span_seconds); - coef_seconds_fast = WIRE2REAL(reply.data.rtc.rtc_seconds_fast); - coef_gain_rate_ppm = WIRE2REAL(reply.data.rtc.rtc_gain_rate_ppm); + coef_seconds_fast = UTI_FloatNetworkToHost(reply.data.rtc.rtc_seconds_fast); + coef_gain_rate_ppm = UTI_FloatNetworkToHost(reply.data.rtc.rtc_gain_rate_ppm); printf("RTC ref time (UTC) : %s", asctime(&ref_time_tm)); printf("Number of samples : %d\n", n_samples); printf("Number of runs : %d\n", n_runs); @@ -2126,9 +2126,9 @@ process_cmd_manual_list(const char *line) for (i=0; iwhen, &when); - slewed_offset = WIRE2REAL(sample->slewed_offset); - orig_offset = WIRE2REAL(sample->orig_offset); - residual = WIRE2REAL(sample->residual); + slewed_offset = UTI_FloatNetworkToHost(sample->slewed_offset); + orig_offset = UTI_FloatNetworkToHost(sample->orig_offset); + residual = UTI_FloatNetworkToHost(sample->residual); printf("%2d %s %10.2f %10.2f %10.2f\n", i, time_to_log_form(when.tv_sec), slewed_offset, orig_offset, residual); } return 1; @@ -2180,8 +2180,8 @@ process_cmd_settime(char *line) if (request_reply(&request, &reply, RPY_MANUAL_TIMESTAMP, 1)) { offset_cs = ntohl(reply.data.manual_timestamp.centiseconds); offset = 0.01 * (double) offset_cs; - dfreq_ppm = WIRE2REAL(reply.data.manual_timestamp.dfreq_ppm); - new_afreq_ppm = WIRE2REAL(reply.data.manual_timestamp.new_afreq_ppm); + dfreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.dfreq_ppm); + new_afreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.new_afreq_ppm); printf("Clock was %.2f seconds fast. Frequency change = %.2fppm, new frequency = %.2fppm\n", offset, dfreq_ppm, new_afreq_ppm); return 1; diff --git a/cmdmon.c b/cmdmon.c index d1e69e4..afcf9c7 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -881,7 +881,7 @@ handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message) IPAddr address; UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address); status = NSR_ModifyMaxdelay(&address, - WIRE2REAL(rx_message->data.modify_maxdelay.new_max_delay)); + UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay)); if (status) { tx_message->status = htons(STT_SUCCESS); } else { @@ -898,7 +898,7 @@ handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message) IPAddr address; UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address); status = NSR_ModifyMaxdelayratio(&address, - WIRE2REAL(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)); + UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)); if (status) { tx_message->status = htons(STT_SUCCESS); } else { @@ -911,7 +911,7 @@ handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message) { - REF_ModifyMaxupdateskew(WIRE2REAL(rx_message->data.modify_maxupdateskew.new_max_update_skew)); + REF_ModifyMaxupdateskew(UTI_FloatNetworkToHost(rx_message->data.modify_maxupdateskew.new_max_update_skew)); tx_message->status = htons(STT_SUCCESS); } @@ -928,8 +928,8 @@ handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->status = htons(STT_SUCCESS); tx_message->reply = htons(RPY_MANUAL_TIMESTAMP); tx_message->data.manual_timestamp.centiseconds = htonl(offset_cs); - tx_message->data.manual_timestamp.dfreq_ppm = REAL2WIRE(dfreq_ppm); - tx_message->data.manual_timestamp.new_afreq_ppm = REAL2WIRE(new_afreq_ppm); + tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm); + tx_message->data.manual_timestamp.new_afreq_ppm = UTI_FloatHostToNetwork(new_afreq_ppm); } else { tx_message->status = htons(STT_NOTENABLED); } @@ -1236,8 +1236,8 @@ handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message) params.authkey = ntohl(rx_message->data.ntp_source.authkey); params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0; params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0; - params.max_delay = WIRE2REAL(rx_message->data.ntp_source.max_delay); - params.max_delay_ratio = WIRE2REAL(rx_message->data.ntp_source.max_delay_ratio); + params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay); + params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio); status = NSR_AddServer(&rem_addr, ¶ms); switch (status) { case NSR_Success: @@ -1276,8 +1276,8 @@ handle_add_peer(CMD_Request *rx_message, CMD_Reply *tx_message) params.authkey = ntohl(rx_message->data.ntp_source.authkey); params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0; params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0; - params.max_delay = WIRE2REAL(rx_message->data.ntp_source.max_delay); - params.max_delay_ratio = WIRE2REAL(rx_message->data.ntp_source.max_delay_ratio); + params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay); + params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio); status = NSR_AddPeer(&rem_addr, ¶ms); switch (status) { case NSR_Success: @@ -1350,7 +1350,7 @@ static void handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message) { double dfreq; - dfreq = WIRE2REAL(rx_message->data.dfreq.dfreq); + dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq); LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6); LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta freq of %.3fppm", dfreq); } @@ -1385,11 +1385,11 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message) UTI_TimevalHostToNetwork(&rpt.ref_time, &tx_message->data.tracking.ref_time); tx_message->data.tracking.current_correction_s = htonl(rpt.current_correction.tv_sec); tx_message->data.tracking.current_correction_us = htonl(rpt.current_correction.tv_usec); - tx_message->data.tracking.freq_ppm = REAL2WIRE(rpt.freq_ppm); - tx_message->data.tracking.resid_freq_ppm = REAL2WIRE(rpt.resid_freq_ppm); - tx_message->data.tracking.skew_ppm = REAL2WIRE(rpt.skew_ppm); - tx_message->data.tracking.root_delay = REAL2WIRE(rpt.root_delay); - tx_message->data.tracking.root_dispersion = REAL2WIRE(rpt.root_dispersion); + tx_message->data.tracking.freq_ppm = UTI_FloatHostToNetwork(rpt.freq_ppm); + tx_message->data.tracking.resid_freq_ppm = UTI_FloatHostToNetwork(rpt.resid_freq_ppm); + tx_message->data.tracking.skew_ppm = UTI_FloatHostToNetwork(rpt.skew_ppm); + tx_message->data.tracking.root_delay = UTI_FloatHostToNetwork(rpt.root_delay); + tx_message->data.tracking.root_dispersion = UTI_FloatHostToNetwork(rpt.root_dispersion); } /* ================================================== */ @@ -1410,9 +1410,9 @@ handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->data.sourcestats.n_samples = htonl(report.n_samples); tx_message->data.sourcestats.n_runs = htonl(report.n_runs); tx_message->data.sourcestats.span_seconds = htonl(report.span_seconds); - tx_message->data.sourcestats.resid_freq_ppm = REAL2WIRE(report.resid_freq_ppm); - tx_message->data.sourcestats.skew_ppm = REAL2WIRE(report.skew_ppm); tx_message->data.sourcestats.sd_us = htonl((unsigned long) (0.5 + report.sd_us)); + tx_message->data.sourcestats.resid_freq_ppm = UTI_FloatHostToNetwork(report.resid_freq_ppm); + tx_message->data.sourcestats.skew_ppm = UTI_FloatHostToNetwork(report.skew_ppm); } else { tx_message->status = htons(STT_NOSUCHSOURCE); } @@ -1433,8 +1433,8 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->data.rtc.n_samples = htons(report.n_samples); tx_message->data.rtc.n_runs = htons(report.n_runs); tx_message->data.rtc.span_seconds = htonl(report.span_seconds); - tx_message->data.rtc.rtc_seconds_fast = REAL2WIRE(report.rtc_seconds_fast); - tx_message->data.rtc.rtc_gain_rate_ppm = REAL2WIRE(report.rtc_gain_rate_ppm); + tx_message->data.rtc.rtc_seconds_fast = UTI_FloatHostToNetwork(report.rtc_seconds_fast); + tx_message->data.rtc.rtc_gain_rate_ppm = UTI_FloatHostToNetwork(report.rtc_gain_rate_ppm); } else { tx_message->status = htons(STT_NORTC); } @@ -1648,9 +1648,9 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message) for (i=0; idata.manual_list.samples[i]; UTI_TimevalHostToNetwork(&report[i].when, &sample->when); - sample->slewed_offset = REAL2WIRE(report[i].slewed_offset); - sample->orig_offset = REAL2WIRE(report[i].orig_offset); - sample->residual = REAL2WIRE(report[i].residual); + sample->slewed_offset = UTI_FloatHostToNetwork(report[i].slewed_offset); + sample->orig_offset = UTI_FloatHostToNetwork(report[i].orig_offset); + sample->residual = UTI_FloatHostToNetwork(report[i].residual); } } diff --git a/util.c b/util.c index 7ee93b8..c55f305 100644 --- a/util.c +++ b/util.c @@ -522,5 +522,77 @@ UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest) dest->tv_sec_low = htonl(src->tv_sec); } +/* ================================================== */ + +#define FLOAT_EXP_BITS 7 +#define FLOAT_EXP_MIN (-(1 << (FLOAT_EXP_BITS - 1))) +#define FLOAT_EXP_MAX (-FLOAT_EXP_MIN - 1) +#define FLOAT_COEF_BITS ((int)sizeof (int32_t) * 8 - FLOAT_EXP_BITS) +#define FLOAT_COEF_MIN (-(1 << (FLOAT_COEF_BITS - 1))) +#define FLOAT_COEF_MAX (-FLOAT_COEF_MIN - 1) + +double +UTI_FloatNetworkToHost(Float f) +{ + int32_t exp, coef, x; + + x = ntohl(f.f); + exp = (x >> FLOAT_COEF_BITS) - FLOAT_COEF_BITS; + coef = x << FLOAT_EXP_BITS >> FLOAT_EXP_BITS; + return coef * pow(2.0, exp); +} + +Float +UTI_FloatHostToNetwork(double x) +{ + int32_t exp, coef, neg; + Float f; + + if (x < 0.0) { + x = -x; + neg = 1; + } else { + neg = 0; + } + + if (x < 1.0e-100) { + exp = coef = 0; + } else if (x > 1.0e100) { + exp = FLOAT_EXP_MAX; + coef = FLOAT_COEF_MAX + neg; + } else { + exp = log(x) / log(2) + 1; + coef = x * pow(2.0, -exp + FLOAT_COEF_BITS) + 0.5; + + assert(coef > 0); + + /* we may need to shift up to two bits down */ + while (coef > FLOAT_COEF_MAX + neg) { + coef >>= 1; + exp++; + } + + if (exp > FLOAT_EXP_MAX) { + /* overflow */ + exp = FLOAT_EXP_MAX; + coef = FLOAT_COEF_MAX + neg; + } else if (exp < FLOAT_EXP_MIN) { + /* underflow */ + if (exp + FLOAT_COEF_BITS >= FLOAT_EXP_MIN) { + coef >>= FLOAT_EXP_MIN - exp; + exp = FLOAT_EXP_MIN; + } else { + exp = coef = 0; + } + } + } + + /* negate back */ + if (neg) + coef = (uint32_t)-coef << FLOAT_EXP_BITS >> FLOAT_EXP_BITS; + + f.f = htonl(exp << FLOAT_COEF_BITS | coef); + return f; +} /* ================================================== */ diff --git a/util.h b/util.h index 31e790c..645659f 100644 --- a/util.h +++ b/util.h @@ -99,6 +99,9 @@ extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest); extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest); extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest); +extern double UTI_FloatNetworkToHost(Float x); +extern Float UTI_FloatHostToNetwork(double x); + #if defined (INLINE_UTILITIES) #define INLINE_STATIC inline static #include "util.c"