O: E148 time-sync drift tracking + quality metric
Extends the existing Clock with the metrics a host needs to gate
time-sensitive data against the equipment's sync state (E148 §6.3):
offset_seconds() current applied offset vs system clock
last_drift_seconds() signed drift observed at the most recent sync
sync_count() how many successful syncs have happened
sync_quality() Synchronized (|drift|<=1s) /
Drifting (<=60s) / Unsynchronized (>60s or
never synced)
The thresholds are tuneable per call; the defaults match typical fab
practice but the application can pass tighter bounds for tracelog-
sensitive flows. set_time_string() now snapshots the apparent delta
between the previously-applied offset and the new one as
last_drift_seconds_ at the moment of resync; no background timer.
Three new test cases cover the initial Unsynchronized state, a large
forward drift registering as Unsynchronized, and a same-value resync
landing as Synchronized.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "secsgem/gem/data_model.hpp"
|
||||
|
||||
using namespace secsgem::gem;
|
||||
@@ -62,6 +64,34 @@ TEST_CASE("set_time_string accepts well-formed and rejects malformed") {
|
||||
CHECK(c.set_time_string("short") == TimeAck::Error);
|
||||
}
|
||||
|
||||
TEST_CASE("Clock: E148 sync quality starts Unsynchronized") {
|
||||
Clock c;
|
||||
CHECK(c.sync_quality() == TimeSyncQuality::Unsynchronized);
|
||||
CHECK(c.sync_count() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Clock: consecutive set_time_string updates record drift") {
|
||||
Clock c;
|
||||
// First sync: drift measured against the (zero) initial offset.
|
||||
REQUIRE(c.set_time_string("20260101000000") == TimeAck::Accept);
|
||||
CHECK(c.sync_count() == 1);
|
||||
|
||||
// Second sync, far in the future: drift should be a large positive number.
|
||||
REQUIRE(c.set_time_string("20270101000000") == TimeAck::Accept);
|
||||
CHECK(c.sync_count() == 2);
|
||||
CHECK(c.last_drift_seconds() > 60 * 60 * 24); // > 1 day
|
||||
CHECK(c.sync_quality() == TimeSyncQuality::Unsynchronized);
|
||||
}
|
||||
|
||||
TEST_CASE("Clock: same-value resync registers as Synchronized") {
|
||||
Clock c;
|
||||
REQUIRE(c.set_time_string("20260601000000") == TimeAck::Accept);
|
||||
// Apply the same target again; the offset doesn't move materially.
|
||||
REQUIRE(c.set_time_string("20260601000000") == TimeAck::Accept);
|
||||
CHECK(std::abs(c.last_drift_seconds()) <= 1);
|
||||
CHECK(c.sync_quality() == TimeSyncQuality::Synchronized);
|
||||
}
|
||||
|
||||
// ---- Host command registry ----------------------------------------------
|
||||
|
||||
TEST_CASE("host command registry returns spec + result") {
|
||||
|
||||
Reference in New Issue
Block a user