blob: 7eb377225fad32ca3ca36e8212d1c25bebca93f9 [file] [log] [blame]
#include "networktables/NetworkTable.h"
#include <algorithm>
#include "llvm/SmallString.h"
#include "llvm/StringMap.h"
#include "tables/ITableListener.h"
#include "tables/TableKeyNotDefinedException.h"
#include "ntcore.h"
using llvm::StringRef;
const char NetworkTable::PATH_SEPARATOR_CHAR = '/';
std::string NetworkTable::s_ip_address;
std::string NetworkTable::s_persistent_filename = "networktables.ini";
bool NetworkTable::s_client = false;
bool NetworkTable::s_running = false;
unsigned int NetworkTable::s_port = NT_DEFAULT_PORT;
void NetworkTable::Initialize() {
if (s_running) Shutdown();
if (s_client)
nt::StartClient(s_ip_address.c_str(), s_port);
else
nt::StartServer(s_persistent_filename, "", s_port);
s_running = true;
}
void NetworkTable::Shutdown() {
if (!s_running) return;
if (s_client)
nt::StopClient();
else
nt::StopServer();
s_running = false;
}
void NetworkTable::SetClientMode() { s_client = true; }
void NetworkTable::SetServerMode() { s_client = false; }
void NetworkTable::SetTeam(int team) {
char tmp[30];
#ifdef _MSC_VER
sprintf_s(tmp, "roboRIO-%d-FRC.local\n", team);
#else
std::snprintf(tmp, 30, "roboRIO-%d-FRC.local\n",team);
#endif
SetIPAddress(tmp);
}
void NetworkTable::SetIPAddress(StringRef address) { s_ip_address = address; }
void NetworkTable::SetPort(unsigned int port) { s_port = port; }
void NetworkTable::SetPersistentFilename(StringRef filename) {
s_persistent_filename = filename;
}
void NetworkTable::SetNetworkIdentity(StringRef name) {
nt::SetNetworkIdentity(name);
}
void NetworkTable::GlobalDeleteAll() { nt::DeleteAllEntries(); }
void NetworkTable::Flush() { nt::Flush(); }
void NetworkTable::SetUpdateRate(double interval) {
nt::SetUpdateRate(interval);
}
const char* NetworkTable::SavePersistent(llvm::StringRef filename) {
return nt::SavePersistent(filename);
}
const char* NetworkTable::LoadPersistent(
llvm::StringRef filename,
std::function<void(size_t line, const char* msg)> warn) {
return nt::LoadPersistent(filename, warn);
}
std::shared_ptr<NetworkTable> NetworkTable::GetTable(StringRef key) {
if (!s_running) Initialize();
llvm::SmallString<128> path;
if (!key.empty()) {
path += PATH_SEPARATOR_CHAR;
path += key;
}
return std::make_shared<NetworkTable>(path, private_init());
}
NetworkTable::NetworkTable(StringRef path, const private_init&)
: m_path(path) {}
NetworkTable::~NetworkTable() {
for (auto& i : m_listeners)
nt::RemoveEntryListener(i.second);
}
void NetworkTable::AddTableListener(ITableListener* listener) {
AddTableListenerEx(listener, NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
}
void NetworkTable::AddTableListener(ITableListener* listener,
bool immediateNotify) {
unsigned int flags = NT_NOTIFY_NEW | NT_NOTIFY_UPDATE;
if (immediateNotify) flags |= NT_NOTIFY_IMMEDIATE;
AddTableListenerEx(listener, flags);
}
void NetworkTable::AddTableListenerEx(ITableListener* listener,
unsigned int flags) {
std::lock_guard<std::mutex> lock(m_mutex);
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
std::size_t prefix_len = path.size();
unsigned int id = nt::AddEntryListener(
path,
[=](unsigned int /*uid*/, StringRef name,
std::shared_ptr<nt::Value> value, unsigned int flags_) {
StringRef relative_key = name.substr(prefix_len);
if (relative_key.find(PATH_SEPARATOR_CHAR) != StringRef::npos) return;
listener->ValueChangedEx(this, relative_key, value, flags_);
},
flags);
m_listeners.emplace_back(listener, id);
}
void NetworkTable::AddTableListener(StringRef key, ITableListener* listener,
bool immediateNotify) {
unsigned int flags = NT_NOTIFY_NEW | NT_NOTIFY_UPDATE;
if (immediateNotify) flags |= NT_NOTIFY_IMMEDIATE;
AddTableListenerEx(key, listener, flags);
}
void NetworkTable::AddTableListenerEx(StringRef key, ITableListener* listener,
unsigned int flags) {
std::lock_guard<std::mutex> lock(m_mutex);
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
std::size_t prefix_len = path.size();
path += key;
unsigned int id = nt::AddEntryListener(
path,
[=](unsigned int /*uid*/, StringRef name, std::shared_ptr<nt::Value> value,
unsigned int flags_) {
if (name != path) return;
listener->ValueChangedEx(this, name.substr(prefix_len), value, flags_);
},
flags);
m_listeners.emplace_back(listener, id);
}
void NetworkTable::AddSubTableListener(ITableListener* listener) {
AddSubTableListener(listener, false);
}
void NetworkTable::AddSubTableListener(ITableListener* listener,
bool localNotify) {
std::lock_guard<std::mutex> lock(m_mutex);
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
std::size_t prefix_len = path.size();
// The lambda needs to be copyable, but StringMap is not, so use
// a shared_ptr to it.
auto notified_tables = std::make_shared<llvm::StringMap<char>>();
unsigned int flags = NT_NOTIFY_NEW | NT_NOTIFY_IMMEDIATE;
if (localNotify) flags |= NT_NOTIFY_LOCAL;
unsigned int id = nt::AddEntryListener(
path,
[=](unsigned int /*uid*/, StringRef name,
std::shared_ptr<nt::Value> /*value*/, unsigned int flags_) mutable {
StringRef relative_key = name.substr(prefix_len);
auto end_sub_table = relative_key.find(PATH_SEPARATOR_CHAR);
if (end_sub_table == StringRef::npos) return;
StringRef sub_table_key = relative_key.substr(0, end_sub_table);
if (notified_tables->find(sub_table_key) == notified_tables->end())
return;
notified_tables->insert(std::make_pair(sub_table_key, '\0'));
listener->ValueChangedEx(this, sub_table_key, nullptr, flags_);
},
flags);
m_listeners.emplace_back(listener, id);
}
void NetworkTable::RemoveTableListener(ITableListener* listener) {
std::lock_guard<std::mutex> lock(m_mutex);
auto matches_begin =
std::remove_if(m_listeners.begin(), m_listeners.end(),
[=](const Listener& x) { return x.first == listener; });
for (auto i = matches_begin; i != m_listeners.end(); ++i)
nt::RemoveEntryListener(i->second);
m_listeners.erase(matches_begin, m_listeners.end());
}
std::shared_ptr<ITable> NetworkTable::GetSubTable(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return std::make_shared<NetworkTable>(path, private_init());
}
bool NetworkTable::ContainsKey(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return nt::GetEntryValue(path) != nullptr;
}
bool NetworkTable::ContainsSubTable(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
path += PATH_SEPARATOR_CHAR;
return !nt::GetEntryInfo(path, 0).empty();
}
std::vector<std::string> NetworkTable::GetKeys(int types) const {
std::vector<std::string> keys;
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
for (auto& entry : nt::GetEntryInfo(path, types)) {
auto relative_key = StringRef(entry.name).substr(path.size());
if (relative_key.find(PATH_SEPARATOR_CHAR) != StringRef::npos)
continue;
keys.push_back(relative_key);
}
return keys;
}
std::vector<std::string> NetworkTable::GetSubTables() const {
std::vector<std::string> keys;
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
for (auto& entry : nt::GetEntryInfo(path, 0)) {
auto relative_key = StringRef(entry.name).substr(path.size());
std::size_t end_subtable = relative_key.find(PATH_SEPARATOR_CHAR);
if (end_subtable == StringRef::npos) continue;
keys.push_back(relative_key.substr(0, end_subtable));
}
return keys;
}
void NetworkTable::SetPersistent(StringRef key) {
SetFlags(key, NT_PERSISTENT);
}
void NetworkTable::ClearPersistent(StringRef key) {
ClearFlags(key, NT_PERSISTENT);
}
bool NetworkTable::IsPersistent(StringRef key) const {
return (GetFlags(key) & NT_PERSISTENT) != 0;
}
void NetworkTable::SetFlags(StringRef key, unsigned int flags) {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
nt::SetEntryFlags(path, nt::GetEntryFlags(key) | flags);
}
void NetworkTable::ClearFlags(StringRef key, unsigned int flags) {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
nt::SetEntryFlags(path, nt::GetEntryFlags(path) & ~flags);
}
unsigned int NetworkTable::GetFlags(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return nt::GetEntryFlags(path);
}
void NetworkTable::Delete(StringRef key) {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
nt::DeleteEntry(path);
}
bool NetworkTable::PutNumber(StringRef key, double value) {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return nt::SetEntryValue(path, nt::Value::MakeDouble(value));
}
double NetworkTable::GetNumber(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
auto value = nt::GetEntryValue(path);
if (!value || value->type() != NT_DOUBLE)
throw TableKeyNotDefinedException(path);
return value->GetDouble();
}
double NetworkTable::GetNumber(StringRef key, double defaultValue) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
auto value = nt::GetEntryValue(path);
if (!value || value->type() != NT_DOUBLE)
return defaultValue;
return value->GetDouble();
}
bool NetworkTable::PutString(StringRef key, StringRef value) {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return nt::SetEntryValue(path, nt::Value::MakeString(value));
}
std::string NetworkTable::GetString(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
auto value = nt::GetEntryValue(path);
if (!value || value->type() != NT_STRING)
throw TableKeyNotDefinedException(path);
return value->GetString();
}
std::string NetworkTable::GetString(StringRef key,
StringRef defaultValue) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
auto value = nt::GetEntryValue(path);
if (!value || value->type() != NT_STRING)
return defaultValue;
return value->GetString();
}
bool NetworkTable::PutBoolean(StringRef key, bool value) {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return nt::SetEntryValue(path, nt::Value::MakeBoolean(value));
}
bool NetworkTable::GetBoolean(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
auto value = nt::GetEntryValue(path);
if (!value || value->type() != NT_BOOLEAN)
throw TableKeyNotDefinedException(path);
return value->GetBoolean();
}
bool NetworkTable::GetBoolean(StringRef key, bool defaultValue) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
auto value = nt::GetEntryValue(path);
if (!value || value->type() != NT_BOOLEAN)
return defaultValue;
return value->GetBoolean();
}
bool NetworkTable::PutValue(StringRef key, std::shared_ptr<nt::Value> value) {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return nt::SetEntryValue(path, value);
}
std::shared_ptr<nt::Value> NetworkTable::GetValue(StringRef key) const {
llvm::SmallString<128> path(m_path);
path += PATH_SEPARATOR_CHAR;
path += key;
return nt::GetEntryValue(path);
}