mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-25 01:41:43 +00:00
[ntcore] Add method to get server time offset (#4847)
Also exposes this as an event signaled when the offset is updated due to a ping response from the server.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -391,6 +392,20 @@ class NetworkTableInstance final {
|
||||
NT_Listener AddConnectionListener(bool immediate_notify,
|
||||
ListenerCallback callback) const;
|
||||
|
||||
/**
|
||||
* Add a time synchronization listener. The callback function is called
|
||||
* asynchronously on a separate thread, so it's important to use
|
||||
* synchronization or atomics when accessing any shared state from the
|
||||
* callback function.
|
||||
*
|
||||
* @param immediate_notify notify listener of current time synchronization
|
||||
* value
|
||||
* @param callback listener to add
|
||||
* @return Listener handle
|
||||
*/
|
||||
NT_Listener AddTimeSyncListener(bool immediate_notify,
|
||||
ListenerCallback callback) const;
|
||||
|
||||
/**
|
||||
* Add a listener for changes on a particular topic. The callback
|
||||
* function is called asynchronously on a separate thread, so it's important
|
||||
@@ -614,6 +629,19 @@ class NetworkTableInstance final {
|
||||
*/
|
||||
bool IsConnected() const;
|
||||
|
||||
/**
|
||||
* Get the time offset between server time and local time. Add this value to
|
||||
* local time to get the estimated equivalent server time. In server mode,
|
||||
* this always returns 0. In client mode, this returns the time offset only if
|
||||
* the client and server are connected and have exchanged synchronization
|
||||
* messages. Note the time offset may change over time as it is periodically
|
||||
* updated; to receive updates as events, add a listener to the "time sync"
|
||||
* event.
|
||||
*
|
||||
* @return Time offset in microseconds (optional)
|
||||
*/
|
||||
std::optional<int64_t> GetServerTimeOffset() const;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,6 +100,13 @@ inline NT_Listener NetworkTableInstance::AddConnectionListener(
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
inline NT_Listener NetworkTableInstance::AddTimeSyncListener(
|
||||
bool immediate_notify, ListenerCallback callback) const {
|
||||
return ::nt::AddListener(
|
||||
m_handle, NT_EVENT_TIMESYNC | (immediate_notify ? NT_EVENT_IMMEDIATE : 0),
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
inline NT_Listener NetworkTableInstance::AddListener(
|
||||
std::span<const std::string_view> prefixes, int eventMask,
|
||||
ListenerCallback listener) {
|
||||
@@ -181,6 +188,11 @@ inline bool NetworkTableInstance::IsConnected() const {
|
||||
return ::nt::IsConnected(m_handle);
|
||||
}
|
||||
|
||||
inline std::optional<int64_t> NetworkTableInstance::GetServerTimeOffset()
|
||||
const {
|
||||
return ::nt::GetServerTimeOffset(m_handle);
|
||||
}
|
||||
|
||||
inline NT_DataLogger NetworkTableInstance::StartEntryDataLog(
|
||||
wpi::log::DataLog& log, std::string_view prefix,
|
||||
std::string_view logPrefix) {
|
||||
|
||||
@@ -106,6 +106,19 @@ class NetworkTableListener final {
|
||||
NetworkTableInstance inst, bool immediate_notify,
|
||||
ListenerCallback listener);
|
||||
|
||||
/**
|
||||
* Create a time synchronization listener.
|
||||
*
|
||||
* @param inst instance
|
||||
* @param immediate_notify notify listener of current time synchronization
|
||||
* value
|
||||
* @param listener listener function
|
||||
* @return Listener
|
||||
*/
|
||||
static NetworkTableListener CreateTimeSyncListener(NetworkTableInstance inst,
|
||||
bool immediate_notify,
|
||||
ListenerCallback listener);
|
||||
|
||||
/**
|
||||
* Create a listener for log messages. By default, log messages are sent to
|
||||
* stderr; this function sends log messages with the specified levels to the
|
||||
@@ -251,6 +264,18 @@ class NetworkTableListenerPoller final {
|
||||
*/
|
||||
NT_Listener AddConnectionListener(bool immediate_notify);
|
||||
|
||||
/**
|
||||
* Add a time synchronization listener. The callback function is called
|
||||
* asynchronously on a separate thread, so it's important to use
|
||||
* synchronization or atomics when accessing any shared state from the
|
||||
* callback function.
|
||||
*
|
||||
* @param immediate_notify notify listener of current time synchronization
|
||||
* value
|
||||
* @return Listener handle
|
||||
*/
|
||||
NT_Listener AddTimeSyncListener(bool immediate_notify);
|
||||
|
||||
/**
|
||||
* Add logger callback function. By default, log messages are sent to stderr;
|
||||
* this function sends log messages with the specified levels to the provided
|
||||
|
||||
@@ -58,6 +58,15 @@ inline NetworkTableListener NetworkTableListener::CreateConnectionListener(
|
||||
std::move(listener))};
|
||||
}
|
||||
|
||||
inline NetworkTableListener NetworkTableListener::CreateTimeSyncListener(
|
||||
NetworkTableInstance inst, bool immediate_notify,
|
||||
ListenerCallback listener) {
|
||||
return NetworkTableListener{::nt::AddListener(
|
||||
inst.GetHandle(),
|
||||
NT_EVENT_TIMESYNC | (immediate_notify ? NT_EVENT_IMMEDIATE : 0),
|
||||
std::move(listener))};
|
||||
}
|
||||
|
||||
inline NetworkTableListener NetworkTableListener::CreateLogger(
|
||||
NetworkTableInstance inst, unsigned int minLevel, unsigned int maxLevel,
|
||||
ListenerCallback listener) {
|
||||
@@ -152,6 +161,13 @@ inline NT_Listener NetworkTableListenerPoller::AddConnectionListener(
|
||||
NT_EVENT_CONNECTION | (immediate_notify ? NT_EVENT_IMMEDIATE : 0));
|
||||
}
|
||||
|
||||
inline NT_Listener NetworkTableListenerPoller::AddTimeSyncListener(
|
||||
bool immediate_notify) {
|
||||
return ::nt::AddPolledListener(
|
||||
m_handle, ::nt::GetInstanceFromHandle(m_handle),
|
||||
NT_EVENT_TIMESYNC | (immediate_notify ? NT_EVENT_IMMEDIATE : 0));
|
||||
}
|
||||
|
||||
inline NT_Listener NetworkTableListenerPoller::AddLogger(
|
||||
unsigned int minLevel, unsigned int maxLevel) {
|
||||
return ::nt::AddPolledLogger(m_handle, minLevel, maxLevel);
|
||||
|
||||
@@ -115,6 +115,8 @@ enum NT_EventFlags {
|
||||
NT_EVENT_VALUE_ALL = NT_EVENT_VALUE_REMOTE | NT_EVENT_VALUE_LOCAL,
|
||||
/** Log message. */
|
||||
NT_EVENT_LOGMESSAGE = 0x100,
|
||||
/** Time synchronized with server. */
|
||||
NT_EVENT_TIMESYNC = 0x200,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -247,6 +249,24 @@ struct NT_LogMessage {
|
||||
char* message;
|
||||
};
|
||||
|
||||
/** NetworkTables time sync event data. */
|
||||
struct NT_TimeSyncEventData {
|
||||
/**
|
||||
* Offset between local time and server time, in microseconds. Add this value
|
||||
* to local time to get the estimated equivalent server time.
|
||||
*/
|
||||
int64_t serverTimeOffset;
|
||||
|
||||
/** Measured round trip time divided by 2, in microseconds. */
|
||||
int64_t rtt2;
|
||||
|
||||
/**
|
||||
* If serverTimeOffset and RTT are valid. An event with this set to false is
|
||||
* sent when the client disconnects.
|
||||
*/
|
||||
NT_Bool valid;
|
||||
};
|
||||
|
||||
/** NetworkTables event */
|
||||
struct NT_Event {
|
||||
/** Listener that triggered this event. */
|
||||
@@ -259,6 +279,7 @@ struct NT_Event {
|
||||
* - NT_EVENT_PUBLISH, NT_EVENT_UNPUBLISH, or NT_EVENT_PROPERTIES: topicInfo
|
||||
* - NT_EVENT_VALUE_REMOTE, NT_NOTIFY_VALUE_LOCAL: valueData
|
||||
* - NT_EVENT_LOGMESSAGE: logMessage
|
||||
* - NT_EVENT_TIMESYNC: timeSyncData
|
||||
*/
|
||||
unsigned int flags;
|
||||
|
||||
@@ -268,6 +289,7 @@ struct NT_Event {
|
||||
struct NT_TopicInfo topicInfo;
|
||||
struct NT_ValueEventData valueData;
|
||||
struct NT_LogMessage logMessage;
|
||||
struct NT_TimeSyncEventData timeSyncData;
|
||||
} data;
|
||||
};
|
||||
|
||||
@@ -1190,6 +1212,22 @@ struct NT_ConnectionInfo* NT_GetConnections(NT_Inst inst, size_t* count);
|
||||
*/
|
||||
NT_Bool NT_IsConnected(NT_Inst inst);
|
||||
|
||||
/**
|
||||
* Get the time offset between server time and local time. Add this value to
|
||||
* local time to get the estimated equivalent server time. In server mode, this
|
||||
* always returns a valid value of 0. In client mode, this returns the time
|
||||
* offset only if the client and server are connected and have exchanged
|
||||
* synchronization messages. Note the time offset may change over time as it is
|
||||
* periodically updated; to receive updates as events, add a listener to the
|
||||
* "time sync" event.
|
||||
*
|
||||
* @param inst instance handle
|
||||
* @param valid set to true if the return value is valid, false otherwise
|
||||
* (output)
|
||||
* @return Time offset in microseconds (if valid is set to true)
|
||||
*/
|
||||
int64_t NT_GetServerTimeOffset(NT_Inst inst, NT_Bool* valid);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -1286,7 +1324,7 @@ void NT_DisposeEvent(struct NT_Event* event);
|
||||
*
|
||||
* @return Timestamp
|
||||
*/
|
||||
uint64_t NT_Now(void);
|
||||
int64_t NT_Now(void);
|
||||
|
||||
/**
|
||||
* Sets the current timestamp used for timestamping values that do not
|
||||
@@ -1297,7 +1335,7 @@ uint64_t NT_Now(void);
|
||||
*
|
||||
* @param timestamp timestamp (1 us increments)
|
||||
*/
|
||||
void NT_SetNow(uint64_t timestamp);
|
||||
void NT_SetNow(int64_t timestamp);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -80,6 +81,8 @@ struct EventFlags {
|
||||
static constexpr unsigned int kValueAll = kValueRemote | kValueLocal;
|
||||
/** Log message. */
|
||||
static constexpr unsigned int kLogMessage = NT_EVENT_LOGMESSAGE;
|
||||
/** Time synchronized with server. */
|
||||
static constexpr unsigned int kTimeSync = NT_EVENT_TIMESYNC;
|
||||
};
|
||||
|
||||
/** NetworkTables Topic Information */
|
||||
@@ -186,6 +189,29 @@ class LogMessage {
|
||||
std::string message;
|
||||
};
|
||||
|
||||
/** NetworkTables time sync event data. */
|
||||
class TimeSyncEventData {
|
||||
public:
|
||||
TimeSyncEventData() = default;
|
||||
TimeSyncEventData(int64_t serverTimeOffset, int64_t rtt2, bool valid)
|
||||
: serverTimeOffset{serverTimeOffset}, rtt2{rtt2}, valid{valid} {}
|
||||
|
||||
/**
|
||||
* Offset between local time and server time, in microseconds. Add this value
|
||||
* to local time to get the estimated equivalent server time.
|
||||
*/
|
||||
int64_t serverTimeOffset;
|
||||
|
||||
/** Measured round trip time divided by 2, in microseconds. */
|
||||
int64_t rtt2;
|
||||
|
||||
/**
|
||||
* If serverTimeOffset and RTT are valid. An event with this set to false is
|
||||
* sent when the client disconnects.
|
||||
*/
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/** NetworkTables event */
|
||||
class Event {
|
||||
public:
|
||||
@@ -208,6 +234,11 @@ class Event {
|
||||
: listener{listener},
|
||||
flags{flags},
|
||||
data{LogMessage{level, filename, line, message}} {}
|
||||
Event(NT_Listener listener, unsigned int flags, int64_t serverTimeOffset,
|
||||
int64_t rtt2, bool valid)
|
||||
: listener{listener},
|
||||
flags{flags},
|
||||
data{TimeSyncEventData{serverTimeOffset, rtt2, valid}} {}
|
||||
|
||||
/** Listener that triggered this event. */
|
||||
NT_Listener listener{0};
|
||||
@@ -215,11 +246,12 @@ class Event {
|
||||
/**
|
||||
* Event flags (NT_EventFlags). Also indicates the data included with the
|
||||
* event:
|
||||
* - NT_NOTIFY_CONNECTED or NT_NOTIFY_DISCONNECTED: GetConnectionInfo()
|
||||
* - NT_NOTIFY_PUBLISH, NT_NOTIFY_UNPUBLISH, or NT_NOTIFY_PROPERTIES:
|
||||
* - NT_EVENT_CONNECTED or NT_EVENT_DISCONNECTED: GetConnectionInfo()
|
||||
* - NT_EVENT_PUBLISH, NT_EVENT_UNPUBLISH, or NT_EVENT_PROPERTIES:
|
||||
* GetTopicInfo()
|
||||
* - NT_NOTIFY_VALUE, NT_NOTIFY_VALUE_LOCAL: GetValueData()
|
||||
* - NT_NOTIFY_LOGMESSAGE: GetLogMessage()
|
||||
* - NT_EVENT_VALUE, NT_EVENT_VALUE_LOCAL: GetValueData()
|
||||
* - NT_EVENT_LOGMESSAGE: GetLogMessage()
|
||||
* - NT_EVENT_TIMESYNC: GetTimeSyncEventData()
|
||||
*/
|
||||
unsigned int flags{0};
|
||||
|
||||
@@ -232,31 +264,40 @@ class Event {
|
||||
bool Is(unsigned int kind) const { return (flags & kind) != 0; }
|
||||
|
||||
/** Event data; content depends on flags. */
|
||||
std::variant<ConnectionInfo, TopicInfo, ValueEventData, LogMessage> data;
|
||||
std::variant<ConnectionInfo, TopicInfo, ValueEventData, LogMessage,
|
||||
TimeSyncEventData>
|
||||
data;
|
||||
|
||||
const ConnectionInfo* GetConnectionInfo() const {
|
||||
return std::get_if<nt::ConnectionInfo>(&data);
|
||||
return std::get_if<ConnectionInfo>(&data);
|
||||
}
|
||||
ConnectionInfo* GetConnectionInfo() {
|
||||
return std::get_if<nt::ConnectionInfo>(&data);
|
||||
return std::get_if<ConnectionInfo>(&data);
|
||||
}
|
||||
|
||||
const TopicInfo* GetTopicInfo() const {
|
||||
return std::get_if<nt::TopicInfo>(&data);
|
||||
return std::get_if<TopicInfo>(&data);
|
||||
}
|
||||
TopicInfo* GetTopicInfo() { return std::get_if<nt::TopicInfo>(&data); }
|
||||
TopicInfo* GetTopicInfo() { return std::get_if<TopicInfo>(&data); }
|
||||
|
||||
const ValueEventData* GetValueEventData() const {
|
||||
return std::get_if<nt::ValueEventData>(&data);
|
||||
return std::get_if<ValueEventData>(&data);
|
||||
}
|
||||
ValueEventData* GetValueEventData() {
|
||||
return std::get_if<nt::ValueEventData>(&data);
|
||||
return std::get_if<ValueEventData>(&data);
|
||||
}
|
||||
|
||||
const LogMessage* GetLogMessage() const {
|
||||
return std::get_if<nt::LogMessage>(&data);
|
||||
return std::get_if<LogMessage>(&data);
|
||||
}
|
||||
LogMessage* GetLogMessage() { return std::get_if<LogMessage>(&data); }
|
||||
|
||||
const TimeSyncEventData* GetTimeSyncEventData() const {
|
||||
return std::get_if<TimeSyncEventData>(&data);
|
||||
}
|
||||
TimeSyncEventData* GetTimeSyncEventData() {
|
||||
return std::get_if<TimeSyncEventData>(&data);
|
||||
}
|
||||
LogMessage* GetLogMessage() { return std::get_if<nt::LogMessage>(&data); }
|
||||
};
|
||||
|
||||
/** NetworkTables publish/subscribe options. */
|
||||
@@ -1107,6 +1148,19 @@ std::vector<ConnectionInfo> GetConnections(NT_Inst inst);
|
||||
*/
|
||||
bool IsConnected(NT_Inst inst);
|
||||
|
||||
/**
|
||||
* Get the time offset between server time and local time. Add this value to
|
||||
* local time to get the estimated equivalent server time. In server mode, this
|
||||
* always returns 0. In client mode, this returns the time offset only if the
|
||||
* client and server are connected and have exchanged synchronization messages.
|
||||
* Note the time offset may change over time as it is periodically updated; to
|
||||
* receive updates as events, add a listener to the "time sync" event.
|
||||
*
|
||||
* @param inst instance handle
|
||||
* @return Time offset in microseconds (optional)
|
||||
*/
|
||||
std::optional<int64_t> GetServerTimeOffset(NT_Inst inst);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user