/* 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. */
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;
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;
} REQ_WriteRtc;
typedef struct {
- int32_t dfreq;
+ Float dfreq;
int32_t EOR;
} REQ_Dfreq;
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
*/
#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 */
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;
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;
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;
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 {
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 {
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 {
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 {
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);
}
}
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));
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));
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);
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);
for (i=0; i<n_samples; i++) {
sample = &reply.data.manual_list.samples[i];
UTI_TimevalNetworkToHost(&sample->when, &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;
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;
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 {
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 {
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);
}
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);
}
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:
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:
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);
}
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);
}
/* ================================================== */
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);
}
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);
}
for (i=0; i<n_samples; i++) {
sample = &tx_message->data.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);
}
}
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;
+}
/* ================================================== */
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"