This adds a new request to get a current report on time smoothing.
#define REQ_RESELECT 48
#define REQ_RESELECTDISTANCE 49
#define REQ_MODIFY_MAKESTEP 50
-#define N_REQUEST_TYPES 51
+#define REQ_SMOOTHING 51
+#define N_REQUEST_TYPES 52
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
#define RPY_MANUAL_LIST 11
#define RPY_ACTIVITY 12
-#define N_REPLY_TYPES 13
+#define RPY_SMOOTHING 13
+#define N_REPLY_TYPES 14
/* Status codes */
#define STT_SUCCESS 0
int32_t EOR;
} RPY_Activity;
+#define RPY_SMT_FLAG_ACTIVE 0x1
+#define RPY_SMT_FLAG_LEAPONLY 0x2
+
+typedef struct {
+ uint32_t flags;
+ Float offset;
+ Float freq_ppm;
+ Float wander_ppm;
+ Float last_update_ago;
+ Float remaining_time;
+ int32_t EOR;
+} RPY_Smoothing;
+
typedef struct {
uint8_t version;
uint8_t pkt_type;
RPY_ClientAccessesByIndex client_accesses_by_index;
RPY_ManualList manual_list;
RPY_Activity activity;
+ RPY_Smoothing smoothing;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data
#include "keys.h"
#include "ntp_sources.h"
#include "ntp_core.h"
+#include "smooth.h"
#include "sources.h"
#include "sourcestats.h"
#include "reference.h"
PERMIT_AUTH, /* RESELECT */
PERMIT_AUTH, /* RESELECTDISTANCE */
PERMIT_AUTH, /* MODIFY_MAKESTEP */
+ PERMIT_OPEN, /* SMOOTHING */
};
/* ================================================== */
/* ================================================== */
+static void
+handle_smoothing(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_SmoothingReport report;
+ struct timeval now;
+
+ SCH_GetLastEventTime(&now, NULL, NULL);
+
+ if (!SMT_GetSmoothingReport(&report, &now)) {
+ tx_message->status = htons(STT_NOTENABLED);
+ return;
+ }
+
+ tx_message->reply = htons(RPY_SMOOTHING);
+ tx_message->data.smoothing.flags = htonl((report.active ? RPY_SMT_FLAG_ACTIVE : 0) |
+ (report.leap_only ? RPY_SMT_FLAG_LEAPONLY : 0));
+ tx_message->data.smoothing.offset = UTI_FloatHostToNetwork(report.offset);
+ tx_message->data.smoothing.freq_ppm = UTI_FloatHostToNetwork(report.freq_ppm);
+ tx_message->data.smoothing.wander_ppm = UTI_FloatHostToNetwork(report.wander_ppm);
+ tx_message->data.smoothing.last_update_ago = UTI_FloatHostToNetwork(report.last_update_ago);
+ tx_message->data.smoothing.remaining_time = UTI_FloatHostToNetwork(report.remaining_time);
+}
+
+/* ================================================== */
+
static void
handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
{
handle_tracking(&rx_message, &tx_message);
break;
+ case REQ_SMOOTHING:
+ handle_smoothing(&rx_message, &tx_message);
+ break;
+
case REQ_SOURCESTATS:
handle_sourcestats(&rx_message, &tx_message);
break;
return offsetof(CMD_Request, data.modify_minstratum.EOR);
case REQ_MODIFY_POLLTARGET:
return offsetof(CMD_Request, data.modify_polltarget.EOR);
+ case REQ_SMOOTHING:
+ return offsetof(CMD_Request, data.null.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
return PADDING_LENGTH(data.modify_minstratum.EOR, data.null.EOR);
case REQ_MODIFY_POLLTARGET:
return PADDING_LENGTH(data.modify_polltarget.EOR, data.null.EOR);
+ case REQ_SMOOTHING:
+ return PADDING_LENGTH(data.null.EOR, data.smoothing.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
}
case RPY_ACTIVITY:
return offsetof(CMD_Reply, data.activity.EOR);
-
+ case RPY_SMOOTHING:
+ return offsetof(CMD_Reply, data.smoothing.EOR);
default:
assert(0);
}
int unresolved;
} RPT_ActivityReport;
+typedef struct {
+ int active;
+ int leap_only;
+ double offset;
+ double freq_ppm;
+ double wander_ppm;
+ double last_update_ago;
+ double remaining_time;
+} RPT_SmoothingReport;
+
#endif /* GOT_REPORTS_H */
static void
-get_offset_freq(struct timeval *now, double *offset, double *freq)
+get_smoothing(struct timeval *now, double *poffset, double *pfreq,
+ double *pwander)
{
- double elapsed, length;
+ double elapsed, length, offset, freq, wander;
int i;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
- *offset = smooth_offset;
- *freq = smooth_freq;
+ offset = smooth_offset;
+ freq = smooth_freq;
+ wander = 0.0;
for (i = 0; i < NUM_STAGES; i++) {
if (elapsed <= 0.0)
if (length >= elapsed)
length = elapsed;
- *offset -= length * (2.0 * *freq + stages[i].wander * length) / 2.0;
- *freq += stages[i].wander * length;
+ wander = stages[i].wander;
+ offset -= length * (2.0 * freq + wander * length) / 2.0;
+ freq += wander * length;
elapsed -= length;
}
- if (elapsed > 0.0)
- *offset -= elapsed * *freq;
+ if (elapsed > 0.0) {
+ wander = 0.0;
+ offset -= elapsed * freq;
+ }
+
+ *poffset = offset;
+ *pfreq = freq;
+ if (pwander)
+ *pwander = wander;
}
static void
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
" (leap seconds only)" : "");
locked = 0;
+ last_update = *now;
}
return;
}
- get_offset_freq(now, &smooth_offset, &smooth_freq);
+ get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
smooth_offset += offset;
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
last_update = *now;
if (!enabled)
return 0.0;
- get_offset_freq(now, &offset, &freq);
+ get_smoothing(now, &offset, &freq, NULL);
return offset;
}
update_smoothing(now, leap, 0.0);
}
+
+int
+SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now)
+{
+ double length, elapsed;
+ int i;
+
+ if (!enabled)
+ return 0;
+
+ report->active = !locked;
+ report->leap_only = leap_only_mode;
+
+ get_smoothing(now, &report->offset, &report->freq_ppm, &report->wander_ppm);
+
+ /* Convert to ppm and negate (positive values mean faster/speeding up) */
+ report->freq_ppm *= -1.0e6;
+ report->wander_ppm *= -1.0e6;
+
+ UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
+ if (!locked && elapsed >= 0.0) {
+ for (i = 0, length = 0.0; i < NUM_STAGES; i++)
+ length += stages[i].length;
+ report->last_update_ago = elapsed;
+ report->remaining_time = elapsed < length ? length - elapsed : 0.0;
+ } else {
+ report->last_update_ago = 0.0;
+ report->remaining_time = 0.0;
+ }
+
+ return 1;
+}
#ifndef GOT_SMOOTH_H
#define GOT_SMOOTH_H
+#include "reports.h"
+
extern void SMT_Initialise(void);
extern void SMT_Finalise(void);
extern void SMT_Leap(struct timeval *now, int leap);
+extern int SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now);
+
#endif