mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
This commit is contained in:
521
src/main/native/include/networktables/NetworkTableInstance.h
Normal file
521
src/main/native/include/networktables/NetworkTableInstance.h
Normal file
@@ -0,0 +1,521 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef NT_INSTANCE_H_
|
||||
#define NT_INSTANCE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
#include "networktables/NetworkTable.h"
|
||||
#include "networktables/NetworkTableEntry.h"
|
||||
#include "ntcore_c.h"
|
||||
#include "ntcore_cpp.h"
|
||||
|
||||
#ifndef NT_NOEXCEPT
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1900
|
||||
#define NT_NOEXCEPT noexcept
|
||||
#else
|
||||
#define NT_NOEXCEPT throw()
|
||||
#endif
|
||||
#else
|
||||
#define NT_NOEXCEPT noexcept
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace nt {
|
||||
|
||||
using llvm::ArrayRef;
|
||||
using llvm::StringRef;
|
||||
|
||||
/** NetworkTables Instance.
|
||||
*
|
||||
* Instances are completely independent from each other. Table operations on
|
||||
* one instance will not be visible to other instances unless the instances are
|
||||
* connected via the network. The main limitation on instances is that you
|
||||
* cannot have two servers on the same network port. The main utility of
|
||||
* instances is for unit testing, but they can also enable one program to
|
||||
* connect to two different NetworkTables networks.
|
||||
*
|
||||
* The global "default" instance (as returned by GetDefault()) is
|
||||
* always available, and is intended for the common case when there is only
|
||||
* a single NetworkTables instance being used in the program. The
|
||||
* default instance cannot be destroyed.
|
||||
*
|
||||
* Additional instances can be created with the Create() function.
|
||||
* Instances are not reference counted or RAII. Instead, they must be
|
||||
* explicitly destroyed (with Destroy()).
|
||||
*/
|
||||
class NetworkTableInstance final {
|
||||
public:
|
||||
/**
|
||||
* Client/server mode flag values (as returned by GetNetworkMode()).
|
||||
* This is a bitmask.
|
||||
*/
|
||||
enum NetworkMode {
|
||||
kNetModeNone = NT_NET_MODE_NONE,
|
||||
kNetModeServer = NT_NET_MODE_SERVER,
|
||||
kNetModeClient = NT_NET_MODE_CLIENT,
|
||||
kNetModeStarting = NT_NET_MODE_STARTING,
|
||||
kNetModeFailure = NT_NET_MODE_FAILURE
|
||||
};
|
||||
|
||||
/**
|
||||
* Logging levels (as used by SetLogger()).
|
||||
*/
|
||||
enum LogLevel {
|
||||
kLogCritical = NT_LOG_CRITICAL,
|
||||
kLogError = NT_LOG_ERROR,
|
||||
kLogWarning = NT_LOG_WARNING,
|
||||
kLogInfo = NT_LOG_INFO,
|
||||
kLogDebug = NT_LOG_DEBUG,
|
||||
kLogDebug1 = NT_LOG_DEBUG1,
|
||||
kLogDebug2 = NT_LOG_DEBUG2,
|
||||
kLogDebug3 = NT_LOG_DEBUG3,
|
||||
kLogDebug4 = NT_LOG_DEBUG4
|
||||
};
|
||||
|
||||
/**
|
||||
* The default port that network tables operates on.
|
||||
*/
|
||||
enum { kDefaultPort = NT_DEFAULT_PORT };
|
||||
|
||||
/**
|
||||
* Construct invalid instance.
|
||||
*/
|
||||
NetworkTableInstance() NT_NOEXCEPT;
|
||||
|
||||
/**
|
||||
* Construct from native handle.
|
||||
* @param handle Native handle
|
||||
*/
|
||||
explicit NetworkTableInstance(NT_Inst inst) NT_NOEXCEPT;
|
||||
|
||||
/**
|
||||
* Determines if the native handle is valid.
|
||||
* @return True if the native handle is valid, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const { return m_handle != 0; }
|
||||
|
||||
/**
|
||||
* Get global default instance.
|
||||
* @return Global default instance
|
||||
*/
|
||||
static NetworkTableInstance GetDefault();
|
||||
|
||||
/**
|
||||
* Create an instance.
|
||||
* @return Newly created instance
|
||||
*/
|
||||
static NetworkTableInstance Create();
|
||||
|
||||
/**
|
||||
* Destroys an instance (note: this has global effect).
|
||||
* @param inst Instance
|
||||
*/
|
||||
static void Destroy(NetworkTableInstance inst);
|
||||
|
||||
/**
|
||||
* Gets the native handle for the entry.
|
||||
* @return Native handle
|
||||
*/
|
||||
NT_Inst GetHandle() const;
|
||||
|
||||
/**
|
||||
* Gets the entry for a key.
|
||||
* @param name Key
|
||||
* @return Network table entry.
|
||||
*/
|
||||
NetworkTableEntry GetEntry(StringRef name);
|
||||
|
||||
/**
|
||||
* Get entries starting with the given prefix.
|
||||
* The results are optionally filtered by string prefix and entry type to
|
||||
* only return a subset of all entries.
|
||||
*
|
||||
* @param prefix entry name required prefix; only entries whose name
|
||||
* starts with this string are returned
|
||||
* @param types bitmask of types; 0 is treated as a "don't care"
|
||||
* @return Array of entries.
|
||||
*/
|
||||
std::vector<NetworkTableEntry> GetEntries(StringRef prefix,
|
||||
unsigned int types);
|
||||
|
||||
/**
|
||||
* Get information about entries starting with the given prefix.
|
||||
* The results are optionally filtered by string prefix and entry type to
|
||||
* only return a subset of all entries.
|
||||
*
|
||||
* @param prefix entry name required prefix; only entries whose name
|
||||
* starts with this string are returned
|
||||
* @param types bitmask of types; 0 is treated as a "don't care"
|
||||
* @return Array of entry information.
|
||||
*/
|
||||
std::vector<EntryInfo> GetEntryInfo(StringRef prefix,
|
||||
unsigned int types) const;
|
||||
|
||||
/**
|
||||
* Gets the table with the specified key.
|
||||
*
|
||||
* @param key the key name
|
||||
* @return The network table
|
||||
*/
|
||||
std::shared_ptr<NetworkTable> GetTable(StringRef key) const;
|
||||
|
||||
/**
|
||||
* Deletes ALL keys in ALL subtables (except persistent values).
|
||||
* Use with caution!
|
||||
*/
|
||||
void DeleteAllEntries();
|
||||
|
||||
/**
|
||||
* @defgroup EntryListenerFunctions Entry Listener Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add a listener for all entries starting with a certain prefix.
|
||||
*
|
||||
* @param prefix UTF-8 string prefix
|
||||
* @param callback listener to add
|
||||
* @param flags EntryListenerFlags bitmask
|
||||
* @return Listener handle
|
||||
*/
|
||||
NT_EntryListener AddEntryListener(
|
||||
StringRef prefix,
|
||||
std::function<void(const EntryNotification& event)> callback,
|
||||
unsigned int flags) const;
|
||||
|
||||
/**
|
||||
* Remove an entry listener.
|
||||
* @param entry_listener Listener handle to remove
|
||||
*/
|
||||
static void RemoveEntryListener(NT_EntryListener entry_listener);
|
||||
|
||||
/**
|
||||
* Wait for the entry listener queue to be empty. This is primarily useful
|
||||
* for deterministic testing. This blocks until either the entry listener
|
||||
* queue is empty (e.g. there are no more events that need to be passed along
|
||||
* to callbacks or poll queues) or the timeout expires.
|
||||
* @param timeout timeout, in seconds. Set to 0 for non-blocking behavior,
|
||||
* or a negative value to block indefinitely
|
||||
* @return False if timed out, otherwise true.
|
||||
*/
|
||||
bool WaitForEntryListenerQueue(double timeout);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup ConnectionListenerFunctions Connection Listener Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add a connection listener.
|
||||
*
|
||||
* @param callback listener to add
|
||||
* @param immediate_notify notify listener of all existing connections
|
||||
* @return Listener handle
|
||||
*/
|
||||
NT_ConnectionListener AddConnectionListener(
|
||||
std::function<void(const ConnectionNotification& event)> callback,
|
||||
bool immediate_notify) const;
|
||||
|
||||
/**
|
||||
* Remove a connection listener.
|
||||
* @param conn_listener Listener handle to remove
|
||||
*/
|
||||
static void RemoveConnectionListener(NT_ConnectionListener conn_listener);
|
||||
|
||||
/**
|
||||
* Wait for the connection listener queue to be empty. This is primarily useful
|
||||
* for deterministic testing. This blocks until either the connection listener
|
||||
* queue is empty (e.g. there are no more events that need to be passed along
|
||||
* to callbacks or poll queues) or the timeout expires.
|
||||
* @param timeout timeout, in seconds. Set to 0 for non-blocking behavior,
|
||||
* or a negative value to block indefinitely
|
||||
* @return False if timed out, otherwise true.
|
||||
*/
|
||||
bool WaitForConnectionListenerQueue(double timeout);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup RpcFunctions Remote Procedure Call Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Wait for the incoming RPC call queue to be empty. This is primarily useful
|
||||
* for deterministic testing. This blocks until either the RPC call
|
||||
* queue is empty (e.g. there are no more events that need to be passed along
|
||||
* to callbacks or poll queues) or the timeout expires.
|
||||
* @param timeout timeout, in seconds. Set to 0 for non-blocking behavior,
|
||||
* or a negative value to block indefinitely
|
||||
* @return False if timed out, otherwise true.
|
||||
*/
|
||||
bool WaitForRpcCallQueue(double timeout);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup NetworkFunctions Client/Server Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the network identity of this node.
|
||||
* This is the name used during the initial connection handshake, and is
|
||||
* visible through ConnectionInfo on the remote node.
|
||||
* @param name identity to advertise
|
||||
*/
|
||||
void SetNetworkIdentity(StringRef name);
|
||||
|
||||
/**
|
||||
* Get the current network mode.
|
||||
* @return Bitmask of NetworkMode.
|
||||
*/
|
||||
unsigned int GetNetworkMode() const;
|
||||
|
||||
/**
|
||||
* Starts a server using the specified filename, listening address, and port.
|
||||
*
|
||||
* @param persist_filename the name of the persist file to use (UTF-8 string,
|
||||
* null terminated)
|
||||
* @param listen_address the address to listen on, or null to listen on any
|
||||
* address (UTF-8 string, null terminated)
|
||||
* @param port port to communicate over
|
||||
*/
|
||||
void StartServer(StringRef persist_filename = "networktables.ini",
|
||||
const char* listen_address = "",
|
||||
unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Stops the server if it is running.
|
||||
*/
|
||||
void StopServer();
|
||||
|
||||
/**
|
||||
* Starts a client. Use SetServer to set the server name and port.
|
||||
*/
|
||||
void StartClient();
|
||||
|
||||
/**
|
||||
* Starts a client using the specified server and port
|
||||
*
|
||||
* @param server_name server name (UTF-8 string, null terminated)
|
||||
* @param port port to communicate over
|
||||
*/
|
||||
void StartClient(const char* server_name, unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Starts a client using the specified (server, port) combinations. The
|
||||
* client will attempt to connect to each server in round robin fashion.
|
||||
*
|
||||
* @param servers array of server name and port pairs
|
||||
*/
|
||||
void StartClient(ArrayRef<std::pair<StringRef, unsigned int>> servers);
|
||||
|
||||
/**
|
||||
* Starts a client using the specified servers and port. The
|
||||
* client will attempt to connect to each server in round robin fashion.
|
||||
*
|
||||
* @param servers array of server names
|
||||
* @param port port to communicate over
|
||||
*/
|
||||
void StartClient(ArrayRef<StringRef> servers,
|
||||
unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Starts a client using commonly known robot addresses for the specified
|
||||
* team.
|
||||
*
|
||||
* @param team team number
|
||||
* @param port port to communicate over
|
||||
*/
|
||||
void StartClientTeam(unsigned int team, unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Stops the client if it is running.
|
||||
*/
|
||||
void StopClient();
|
||||
|
||||
/**
|
||||
* Sets server address and port for client (without restarting client).
|
||||
*
|
||||
* @param server_name server name (UTF-8 string, null terminated)
|
||||
* @param port port to communicate over
|
||||
*/
|
||||
void SetServer(const char* server_name, unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Sets server addresses and ports for client (without restarting client).
|
||||
* The client will attempt to connect to each server in round robin fashion.
|
||||
*
|
||||
* @param servers array of server name and port pairs
|
||||
*/
|
||||
void SetServer(ArrayRef<std::pair<StringRef, unsigned int>> servers);
|
||||
|
||||
/**
|
||||
* Sets server addresses and port for client (without restarting client).
|
||||
* The client will attempt to connect to each server in round robin fashion.
|
||||
*
|
||||
* @param servers array of server names
|
||||
* @param port port to communicate over
|
||||
*/
|
||||
void SetServer(ArrayRef<StringRef> servers, unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Sets server addresses and port for client (without restarting client).
|
||||
* Connects using commonly known robot addresses for the specified team.
|
||||
*
|
||||
* @param team team number
|
||||
* @param port port to communicate over
|
||||
*/
|
||||
void SetServerTeam(unsigned int team, unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Starts requesting server address from Driver Station.
|
||||
* This connects to the Driver Station running on localhost to obtain the
|
||||
* server IP address.
|
||||
*
|
||||
* @param port server port to use in combination with IP from DS
|
||||
*/
|
||||
void StartDSClient(unsigned int port = kDefaultPort);
|
||||
|
||||
/**
|
||||
* Stops requesting server address from Driver Station.
|
||||
*/
|
||||
void StopDSClient();
|
||||
|
||||
/**
|
||||
* Set the periodic update rate.
|
||||
* Sets how frequently updates are sent to other nodes over the network.
|
||||
*
|
||||
* @param interval update interval in seconds (range 0.01 to 1.0)
|
||||
*/
|
||||
void SetUpdateRate(double interval);
|
||||
|
||||
/**
|
||||
* Flushes all updated values immediately to the network.
|
||||
* @note This is rate-limited to protect the network from flooding.
|
||||
* This is primarily useful for synchronizing network updates with
|
||||
* user code.
|
||||
*/
|
||||
void Flush() const;
|
||||
|
||||
/**
|
||||
* Get information on the currently established network connections.
|
||||
* If operating as a client, this will return either zero or one values.
|
||||
* @return array of connection information
|
||||
*/
|
||||
std::vector<ConnectionInfo> GetConnections() const;
|
||||
|
||||
/**
|
||||
* Return whether or not the instance is connected to another node.
|
||||
* @return True if connected.
|
||||
*/
|
||||
bool IsConnected() const;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup PersistentFunctions Persistent Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Save persistent values to a file. The server automatically does this,
|
||||
* but this function provides a way to save persistent values in the same
|
||||
* format to a file on either a client or a server.
|
||||
* @param filename filename
|
||||
* @return error string, or nullptr if successful
|
||||
*/
|
||||
const char* SavePersistent(StringRef filename) const;
|
||||
|
||||
/**
|
||||
* Load persistent values from a file. The server automatically does this
|
||||
* at startup, but this function provides a way to restore persistent values
|
||||
* in the same format from a file at any time on either a client or a server.
|
||||
* @param filename filename
|
||||
* @param warn callback function for warnings
|
||||
* @return error string, or nullptr if successful
|
||||
*/
|
||||
const char* LoadPersistent(
|
||||
StringRef filename,
|
||||
std::function<void(size_t line, const char* msg)> warn);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup LoggerFunctions Logger Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add logger callback function. By default, log messages are sent to stderr;
|
||||
* this function sends log messages with the specified levels to the provided
|
||||
* callback function instead. The callback function will only be called for
|
||||
* log messages with level greater than or equal to minLevel and less than or
|
||||
* equal to maxLevel; messages outside this range will be silently ignored.
|
||||
*
|
||||
* @param func log callback function
|
||||
* @param minLevel minimum log level
|
||||
* @param maxLevel maximum log level
|
||||
* @return Logger handle
|
||||
*/
|
||||
NT_Logger AddLogger(std::function<void(const LogMessage& msg)> func,
|
||||
unsigned int min_level, unsigned int max_level);
|
||||
|
||||
/**
|
||||
* Remove a logger.
|
||||
* @param logger Logger handle to remove
|
||||
*/
|
||||
static void RemoveLogger(NT_Logger logger);
|
||||
|
||||
/**
|
||||
* Wait for the incoming log event queue to be empty. This is primarily useful
|
||||
* for deterministic testing. This blocks until either the log event
|
||||
* queue is empty (e.g. there are no more events that need to be passed along
|
||||
* to callbacks or poll queues) or the timeout expires.
|
||||
* @param timeout timeout, in seconds. Set to 0 for non-blocking behavior,
|
||||
* or a negative value to block indefinitely
|
||||
* @return False if timed out, otherwise true.
|
||||
*/
|
||||
bool WaitForLoggerQueue(double timeout);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Equality operator. Returns true if both instances refer to the same
|
||||
* native handle.
|
||||
*/
|
||||
bool operator==(const NetworkTableInstance& other) const {
|
||||
return m_handle == other.m_handle;
|
||||
}
|
||||
|
||||
/** Inequality operator. */
|
||||
bool operator!=(const NetworkTableInstance& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
/* Native handle */
|
||||
NT_Inst m_handle;
|
||||
};
|
||||
|
||||
} // namespace nt
|
||||
|
||||
#include "networktables/NetworkTableInstance.inl"
|
||||
|
||||
#endif // NT_INSTANCE_H_
|
||||
Reference in New Issue
Block a user