16using TimestampType = std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds>;
88 _current_drift_fe(0.0),
93 _leader_has_changed_flag(
false),
96 db<Clock>(
INF) <<
"Clock: Initialized in UNSYNCHRONIZED state\n";
101 void doClearSyncData();
108 bool isLeaderMessageTimedOut()
const;
110 bool isLeaderAssigned()
const;
114 std::atomic<State> _currentState;
115 mutable std::mutex _mutex;
129 std::atomic<bool> _leader_has_changed_flag;
136 static constexpr DurationType MAX_LEADER_SILENCE_INTERVAL = std::chrono::microseconds(500000);
146 static Clock instance;
157 std::lock_guard<std::mutex>
lock(_mutex);
160 db<Clock>(
INF) <<
"Clock: Self ID set to " << _self_id <<
"\n";
163 db<Clock>(
WRN) <<
"Clock: Attempt to change self ID from " << _self_id
164 <<
" to " <<
id <<
". Current self ID maintained.\n";
165 }
else if (
id == _self_id) {
167 db<Clock>(
TRC) <<
"Clock: Self ID re-confirmed to " << _self_id <<
"\n";
178 std::lock_guard<std::mutex>
lock(_mutex);
190 if (_currentState.load(std::memory_order_acquire) !=
State::SYNCHRONIZED || _current_leader_id != _self_id) {
191 db<Clock>(
INF) <<
"Clock: This node (" << _self_id <<
") is the PTP leader. Forcing SYNCHRONIZED state.\n";
193 _current_leader_id = _self_id;
194 _current_offset = DurationType::zero();
195 _current_drift_fe = 0.0;
197 _leader_time_at_last_sync_event = _local_time_at_last_sync_event;
200 _leader_has_changed_flag.store(
false, std::memory_order_release);
223 if (isLeaderMessageTimedOut()) {
234 if (isLeaderMessageTimedOut()) {
247 _currentState.store(
new_state, std::memory_order_release);
258 std::lock_guard<std::mutex>
lock(_mutex);
263 db<Clock>(
INF) <<
"Clock::getSynchronizedTime WARNING: Clock UNSYNCHRONIZED. Returning local hardware time.\n";
300 std::lock_guard<std::mutex>
lock(_mutex);
311 std::lock_guard<std::mutex>
lock(_mutex);
319 db<Clock>(
INF) <<
"Clock::getState: This node (" << _self_id <<
") is leader. Correcting state to SYNCHRONIZED.\n";
329 if (isLeaderMessageTimedOut()) {
330 db<Clock>(
INF) <<
"Clock: Timeout detected, transitioning to UNSYNCHRONIZED\n";
346 std::lock_guard<std::mutex>
lock(_mutex);
347 return _current_leader_id;
352 return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::steady_clock::now());
366 return MAX_LEADER_SILENCE_INTERVAL;
376 std::lock_guard<std::mutex>
lock(_mutex);
383inline void Clock::doClearSyncData() {
386 _current_offset = DurationType::zero();
387 _current_drift_fe = 0.0;
388 _leader_time_at_last_sync_event = TimestampType::min();
390 _leader_has_changed_flag.store(
false, std::memory_order_release);
396 _last_sync_local_time =
now;
400 _msg1_data.
d_tx_calc = std::chrono::microseconds(2);
406 _local_time_at_last_sync_event = _msg1_data.
ts_local_rx;
407 _current_drift_fe = 0.0;
409 db<Clock>(
INF) <<
"Clock: Processed first leader message. Offset: "
410 << _current_offset.count() <<
"us\n";
415 _last_sync_local_time =
now;
419 _msg2_data.
d_tx_calc = std::chrono::microseconds(2);
424 _current_offset =
o2;
437 _local_time_at_last_sync_event = _msg2_data.
ts_local_rx;
439 db<Clock>(
INF) <<
"Clock: Processed second leader message. New Offset: "
440 << _current_offset.count() <<
"us, Drift FE: " << _current_drift_fe <<
"\n";
443 " Local rx timestamps: " << _msg1_data.
ts_local_rx.time_since_epoch().count() <<
444 " " << _msg2_data.
ts_local_rx.time_since_epoch().count() <<
"\n";
449 _last_sync_local_time =
now;
451 _msg1_data = _msg2_data;
452 doProcessSecondLeaderMsgAndCalcDrift(
msg_data);
454 db<Clock>(
INF) <<
"Clock: Processed subsequent leader message. Updated Offset: "
455 << _current_offset.count() <<
"us, Updated Drift FE: " << _current_drift_fe <<
"\n";
458inline bool Clock::isLeaderMessageTimedOut()
const {
465 if (_local_time_at_last_sync_event == TimestampType::min() || !isLeaderAssigned()) {
470 return (
local_hw_now - _last_sync_local_time) > MAX_LEADER_SILENCE_INTERVAL;
474 return msg_data.sender_id == _current_leader_id;
477inline bool Clock::isLeaderAssigned()
const {
495 db<Clock>(
INF) <<
"Clock: Leader changed from " << _current_leader_id
509 return os <<
"UNSYNCHRONIZED";
511 return os <<
"AWAITING_SECOND_MSG";
513 return os <<
"SYNCHRONIZED";
515 return os <<
"UNKNOWN_STATE";
Thread-safe singleton for PTP clock synchronization.
Definition clock.h:56
State getState()
Get current synchronization state.
Definition clock.h:310
void reset()
Reset the Clock singleton to its initial state (for testing only)
Definition clock.h:374
Clock & operator=(const Clock &)=delete
void setSelfId(LeaderIdType id)
Set the self ID for this clock instance (node's own PTP-relevant ID)
Definition clock.h:156
DurationType getMaxLeaderSilenceInterval() const
Definition clock.h:365
void activate(const PtpRelevantData *new_msg_data)
Activate the state machine with new PTP data.
Definition clock.h:177
State
Definition clock.h:58
TimestampType getLocalSteadyHardwareTime() const
Definition clock.h:351
LeaderIdType getCurrentLeader() const
Get the current PTP leader ID.
Definition clock.h:345
TimestampType getSynchronizedTime(bool *is_synchronized)
Get the current synchronized time.
Definition clock.h:257
TimestampType getLocalSystemTime()
Definition clock.h:356
Clock(const Clock &)=delete
static Clock & getInstance()
Get the singleton instance.
Definition clock.h:145
bool isFullySynchronized() const
Check if clock is fully synchronized.
Definition clock.h:299
static LeaderKeyStorage & getInstance()
Get the singleton instance.
Definition leaderKeyStorage.h:54
double FrequencyErrorType
Definition clock.h:22
uint32_t LeaderIdType
Definition clock.h:26
std::chrono::time_point< std::chrono::steady_clock, std::chrono::microseconds > TimestampType
Definition clock.h:16
std::ostream & operator<<(std::ostream &os, Clock::State state)
Definition clock.h:506
const LeaderIdType INVALID_LEADER_ID
Definition clock.h:27
std::chrono::microseconds DurationType
Definition clock.h:19
@ INF
Definition debug.h:208
Select_Debug<(Traits< T >::debugged &&Traits< Debug >::error)> db(Debug_Error l)
Definition debug.h:166
@ TRC
Definition debug.h:231
@ WRN
Definition debug.h:185
std::uint8_t bytes[MAC_SIZE]
Definition ethernet.h:17
TimestampType ts_local_rx
Definition clock.h:39
PtpInternalMessageInfo()=default
TimestampType leader_time_at_local_rx_event
Definition clock.h:41
DurationType d_tx_calc
Definition clock.h:40
TimestampType ts_tx_at_sender
Definition clock.h:38
TimestampType ts_tx_at_sender
Definition clock.h:32
TimestampType ts_local_rx
Definition clock.h:33
LeaderIdType sender_id
Definition clock.h:31