/*----------------------------------------------------------------------------*/ /* Copyright (c) FIRST 2017-2018. 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 NTCORE_NETWORKTABLES_NETWORKTABLEINSTANCE_H_ #define NTCORE_NETWORKTABLES_NETWORKTABLEINSTANCE_H_ #include #include #include #include #include #include #include #include #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; using llvm::Twine; /** 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(const Twine& 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 GetEntries(const Twine& 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 GetEntryInfo(const Twine& prefix, unsigned int types) const; /** * Gets the table with the specified key. * * @param key the key name * @return The network table */ std::shared_ptr GetTable(const Twine& 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( const Twine& prefix, std::function 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 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(const Twine& 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(const Twine& 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> 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 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> 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 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 GetConnections() const; /** * Return whether or not the instance is connected to another node. * @return True if connected. */ bool IsConnected() const; /** @} */ /** * @defgroup FileFunctions File Save/Load 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(const Twine& 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( const Twine& filename, std::function warn); /** * Save table values to a file. The file format used is identical to * that used for SavePersistent. * @param filename filename * @param prefix save only keys starting with this prefix * @return error string, or nullptr if successful */ const char* SaveEntries(const Twine& filename, const Twine& prefix) const; /** * Load table values from a file. The file format used is identical to * that used for SavePersistent / LoadPersistent. * @param filename filename * @param prefix load only keys starting with this prefix * @param warn callback function for warnings * @return error string, or nullptr if successful */ const char* LoadEntries( const Twine& filename, const Twine& prefix, std::function 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 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 // NTCORE_NETWORKTABLES_NETWORKTABLEINSTANCE_H_