mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-01 02:41:48 +00:00
Initial checkin of unified hierarchy of WPILib 2015
This commit is contained in:
54
networktables/cpp/parent/pom.xml
Normal file
54
networktables/cpp/parent/pom.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.cpp</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<version>1.0-alpha-7</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>
|
||||
<directory>src/main/native</directory>
|
||||
<includes>
|
||||
<include>**/*.cpp</include>
|
||||
</includes>
|
||||
</source>
|
||||
<source>
|
||||
<directory>../parent/src/main/native</directory>
|
||||
<includes>
|
||||
<include>**/*.cpp</include>
|
||||
</includes>
|
||||
</source>
|
||||
</sources>
|
||||
<compilerStartOptions>
|
||||
<compilerStartOptions>-Wall -O3 -Wextra -Wno-unused-parameter -pedantic -Wpointer-arith -Wswitch-default -Wswitch-enum -Wundef -Wuninitialized</compilerStartOptions>
|
||||
</compilerStartOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<local-repository>C:/Users/wpilibj-buildmaster/maven-repository</local-repository>
|
||||
</properties>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jenkins</id>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>myrepository</id>
|
||||
<url>file:${local-repository}</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,340 @@
|
||||
#include <map>
|
||||
#include "networktables/NetworkTable.h"
|
||||
#include <string>
|
||||
#include "networktables2/thread/NTThreadManager.h"
|
||||
#include "networktables2/thread/DefaultThreadManager.h"
|
||||
#include "networktables2/NetworkTableEntry.h"
|
||||
#include "networktables2/util/StringCache.h"
|
||||
#include "networktables/NetworkTableProvider.h"
|
||||
#include "networktables/NetworkTableMode.h"
|
||||
#include "OSAL/Synchronized.h"
|
||||
#include "tables/TableKeyNotDefinedException.h"
|
||||
#include "networktables2/type/DefaultEntryTypes.h"
|
||||
#include "tables/ITableListener.h"
|
||||
#include "networktables/NetworkTableConnectionListenerAdapter.h"
|
||||
#include "networktables/NetworkTableKeyListenerAdapter.h"
|
||||
#include "networktables/NetworkTableListenerAdapter.h"
|
||||
#include "networktables/NetworkTableSubListenerAdapter.h"
|
||||
|
||||
|
||||
const char NetworkTable::PATH_SEPARATOR_CHAR = '/';
|
||||
const std::string NetworkTable::PATH_SEPARATOR("/");
|
||||
const int NetworkTable::DEFAULT_PORT = 1735;
|
||||
|
||||
DefaultThreadManager NetworkTable::threadManager;
|
||||
NetworkTableProvider* NetworkTable::staticProvider = NULL;
|
||||
NetworkTableNode* NetworkTable::staticNode = NULL;
|
||||
void* NetworkTable::streamFactory = NULL;
|
||||
NetworkTableEntryTypeManager* NetworkTable::typeManager = NULL;
|
||||
StreamDeleter streamDeleter = NULL;
|
||||
NetworkTableMode* NetworkTable::mode = &NetworkTableMode::Server;
|
||||
int NetworkTable::port = DEFAULT_PORT;
|
||||
std::string NetworkTable::ipAddress;
|
||||
NTReentrantSemaphore NetworkTable::STATIC_LOCK;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void NetworkTable::CheckInit(){
|
||||
printf("[NT] NetworkTable::CheckInit()...\n");
|
||||
{
|
||||
NTSynchronized sync(STATIC_LOCK);
|
||||
if(staticProvider!=NULL)
|
||||
throw new IllegalStateException("Network tables has already been initialized");
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTable::Initialize() {
|
||||
CheckInit();
|
||||
printf("[NT] NetworkTable::Initialize()...\n");
|
||||
staticProvider = new NetworkTableProvider(*(staticNode = mode->CreateNode(ipAddress.c_str(), port, threadManager, streamFactory, streamDeleter, typeManager)));
|
||||
printf("[NT] ...NetworkTable::Initialize().\n");
|
||||
}
|
||||
|
||||
void NetworkTable::Shutdown()
|
||||
{
|
||||
if (staticProvider!=NULL)
|
||||
{
|
||||
delete staticProvider;
|
||||
staticProvider=NULL;
|
||||
}
|
||||
if (staticNode!=NULL)
|
||||
{
|
||||
delete staticNode;
|
||||
staticNode=NULL;
|
||||
}
|
||||
if (streamDeleter!=NULL && streamFactory!=NULL)
|
||||
{
|
||||
streamDeleter(streamFactory);
|
||||
streamFactory=NULL;
|
||||
streamDeleter=NULL;
|
||||
}
|
||||
if (typeManager!=NULL)
|
||||
{
|
||||
delete typeManager;
|
||||
typeManager=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTable::SetTableProvider(NetworkTableProvider* provider){
|
||||
CheckInit();
|
||||
staticProvider = provider;
|
||||
}
|
||||
|
||||
void NetworkTable::SetClientMode(){
|
||||
CheckInit();
|
||||
mode = &NetworkTableMode::Client;
|
||||
}
|
||||
|
||||
void NetworkTable::SetServerMode(){
|
||||
CheckInit();
|
||||
mode = &NetworkTableMode::Server;
|
||||
}
|
||||
|
||||
void NetworkTable::SetTeam(int team){
|
||||
char tmp[30];
|
||||
sprintf(tmp, "%d.%d.%d.%d\n", 10, team/100, team%100, 2);
|
||||
SetIPAddress(tmp);
|
||||
}
|
||||
|
||||
void NetworkTable::SetIPAddress(const char* address){
|
||||
CheckInit();
|
||||
ipAddress = address;
|
||||
}
|
||||
|
||||
NetworkTable* NetworkTable::GetTable(std::string key) {
|
||||
printf("[NT] NetworkTable::GetTable()...\n");
|
||||
if(staticProvider==NULL){
|
||||
printf("[NT] \tInitializing...\n");
|
||||
Initialize();
|
||||
}
|
||||
std::string tmp(PATH_SEPARATOR);
|
||||
tmp+=key;
|
||||
printf("[NT] ...Ready to get Table.\n");
|
||||
return (NetworkTable*)staticProvider->GetTable(tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
NetworkTable::NetworkTable(std::string _path, NetworkTableProvider& _provider) :
|
||||
path(_path), entryCache(_path), absoluteKeyCache(_path), provider(_provider), node(provider.GetNode()) {
|
||||
}
|
||||
NetworkTable::~NetworkTable(){
|
||||
}
|
||||
|
||||
bool NetworkTable::IsConnected() {
|
||||
return node.IsConnected();
|
||||
}
|
||||
|
||||
bool NetworkTable::IsServer() {
|
||||
return node.IsServer();
|
||||
}
|
||||
|
||||
|
||||
void NetworkTable::AddConnectionListener(IRemoteConnectionListener* listener, bool immediateNotify) {
|
||||
map<IRemoteConnectionListener*, NetworkTableConnectionListenerAdapter*>::iterator itr = connectionListenerMap.find(listener);
|
||||
if(itr != connectionListenerMap.end()){
|
||||
throw IllegalStateException("Cannot add the same listener twice");
|
||||
}
|
||||
else{
|
||||
NetworkTableConnectionListenerAdapter* adapter = new NetworkTableConnectionListenerAdapter(this, listener);
|
||||
connectionListenerMap[listener] = adapter;
|
||||
node.AddConnectionListener(adapter, immediateNotify);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTable::RemoveConnectionListener(IRemoteConnectionListener* listener) {
|
||||
map<IRemoteConnectionListener*, NetworkTableConnectionListenerAdapter*>::iterator itr = connectionListenerMap.find(listener);
|
||||
if(itr != connectionListenerMap.end()){
|
||||
node.RemoveConnectionListener(itr->second);
|
||||
delete itr->second;
|
||||
connectionListenerMap.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NetworkTable::AddTableListener(ITableListener* listener) {
|
||||
AddTableListener(listener, false);
|
||||
}
|
||||
|
||||
void NetworkTable::AddTableListener(ITableListener* listener, bool immediateNotify) {
|
||||
std::string tmp(path);
|
||||
tmp+=PATH_SEPARATOR;
|
||||
NetworkTableListenerAdapter* adapter = new NetworkTableListenerAdapter(tmp, this, listener);
|
||||
listenerMap.insert ( pair<ITableListener*,ITableListener*>(listener, adapter) );
|
||||
node.AddTableListener(adapter, immediateNotify);
|
||||
}
|
||||
void NetworkTable::AddTableListener(std::string key, ITableListener* listener, bool immediateNotify) {
|
||||
NetworkTableKeyListenerAdapter* adapter = new NetworkTableKeyListenerAdapter(key, absoluteKeyCache.Get(key), this, listener);
|
||||
listenerMap.insert ( pair<ITableListener*,ITableListener*>(listener, adapter) );
|
||||
node.AddTableListener(adapter, immediateNotify);
|
||||
}
|
||||
void NetworkTable::AddSubTableListener(ITableListener* listener) {
|
||||
NetworkTableSubListenerAdapter* adapter = new NetworkTableSubListenerAdapter(path, this, listener);
|
||||
listenerMap.insert ( pair<ITableListener*,ITableListener*>(listener, adapter) );
|
||||
node.AddTableListener(adapter, true);
|
||||
}
|
||||
|
||||
void NetworkTable::RemoveTableListener(ITableListener* listener) {
|
||||
multimap<ITableListener*,ITableListener*>::iterator itr;
|
||||
pair<multimap<ITableListener*,ITableListener*>::iterator,multimap<ITableListener*,ITableListener*>::iterator> itrs = listenerMap.equal_range(listener);
|
||||
for (itr=itrs.first; itr!=itrs.second; ++itr){
|
||||
node.RemoveTableListener(itr->second);
|
||||
delete itr->second;
|
||||
}
|
||||
listenerMap.erase(itrs.first, itrs.second);
|
||||
}
|
||||
|
||||
NetworkTableEntry* NetworkTable::GetEntry(std::string key){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
return entryCache.Get(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NetworkTable* NetworkTable::GetSubTable(std::string key) {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
return (NetworkTable*)provider.GetTable(absoluteKeyCache.Get(key));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool NetworkTable::ContainsKey(std::string key) {
|
||||
return node.ContainsKey(absoluteKeyCache.Get(key));
|
||||
}
|
||||
|
||||
bool NetworkTable::ContainsSubTable(std::string key){
|
||||
std::string subtablePrefix(absoluteKeyCache.Get(key));
|
||||
subtablePrefix+=PATH_SEPARATOR;
|
||||
std::vector<std::string>* keys = node.GetEntryStore().keys();
|
||||
for(unsigned int i = 0; i<keys->size(); ++i){
|
||||
if(keys->at(i).compare(0, subtablePrefix.size(), subtablePrefix)==0){
|
||||
delete keys;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
delete keys;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void NetworkTable::PutNumber(std::string key, double value) {
|
||||
EntryValue eValue;
|
||||
eValue.f = value;
|
||||
PutValue(key, &DefaultEntryTypes::DOUBLE, eValue);
|
||||
}
|
||||
|
||||
|
||||
double NetworkTable::GetNumber(std::string key) {
|
||||
return node.GetDouble(absoluteKeyCache.Get(key));
|
||||
}
|
||||
|
||||
|
||||
double NetworkTable::GetNumber(std::string key, double defaultValue) {
|
||||
try {
|
||||
return node.GetDouble(absoluteKeyCache.Get(key));
|
||||
} catch (TableKeyNotDefinedException& e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NetworkTable::PutString(std::string key, std::string value) {
|
||||
EntryValue eValue;
|
||||
eValue.ptr = &value;
|
||||
PutValue(key, &DefaultEntryTypes::STRING, eValue);
|
||||
}
|
||||
|
||||
|
||||
std::string NetworkTable::GetString(std::string key) {
|
||||
return node.GetString(absoluteKeyCache.Get(key));
|
||||
}
|
||||
|
||||
|
||||
std::string NetworkTable::GetString(std::string key, std::string defaultValue) {
|
||||
try {
|
||||
return node.GetString(absoluteKeyCache.Get(key));
|
||||
} catch (TableKeyNotDefinedException& e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NetworkTable::PutBoolean(std::string key, bool value) {
|
||||
EntryValue eValue;
|
||||
eValue.b = value;
|
||||
PutValue(key, &DefaultEntryTypes::BOOLEAN, eValue);
|
||||
}
|
||||
|
||||
|
||||
bool NetworkTable::GetBoolean(std::string key) {
|
||||
return node.GetBoolean(absoluteKeyCache.Get(key));
|
||||
}
|
||||
|
||||
|
||||
bool NetworkTable::GetBoolean(std::string key, bool defaultValue) {
|
||||
try {
|
||||
return node.GetBoolean(absoluteKeyCache.Get(key));
|
||||
} catch (TableKeyNotDefinedException& e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTable::PutValue(std::string key, NetworkTableEntryType* type, EntryValue value){
|
||||
NetworkTableEntry* entry = entryCache.Get(key);
|
||||
if(entry!=NULL)
|
||||
node.PutValue(entry, value);//TODO pass type along or do some kind of type check
|
||||
else
|
||||
node.PutValue(absoluteKeyCache.Get(key), type, value);
|
||||
}
|
||||
|
||||
void NetworkTable::RetrieveValue(std::string key, ComplexData& externalValue) {
|
||||
node.retrieveValue(absoluteKeyCache.Get(key), externalValue);
|
||||
}
|
||||
|
||||
|
||||
void NetworkTable::PutValue(std::string key, ComplexData& value){
|
||||
EntryValue eValue;
|
||||
eValue.ptr = &value;
|
||||
PutValue(key, &value.GetType(), eValue);
|
||||
}
|
||||
|
||||
|
||||
EntryValue NetworkTable::GetValue(std::string key) {
|
||||
return node.GetValue(absoluteKeyCache.Get(key));
|
||||
}
|
||||
|
||||
EntryValue NetworkTable::GetValue(std::string key, EntryValue defaultValue) {
|
||||
try {
|
||||
return node.GetValue(absoluteKeyCache.Get(key));
|
||||
} catch(TableKeyNotDefinedException& e){
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//NetworkTableKeyCache
|
||||
NetworkTableKeyCache::NetworkTableKeyCache(std::string _path):path(_path){}
|
||||
NetworkTableKeyCache::~NetworkTableKeyCache(){}
|
||||
std::string NetworkTableKeyCache::Calc(const std::string& key){
|
||||
std::string tmp(path);
|
||||
tmp+=NetworkTable::PATH_SEPARATOR;
|
||||
tmp+=key;
|
||||
return tmp;
|
||||
}
|
||||
//Entry Cache
|
||||
EntryCache::EntryCache(std::string& _path):path(_path){}
|
||||
EntryCache::~EntryCache(){}
|
||||
|
||||
NetworkTableEntry* EntryCache::Get(std::string& key){
|
||||
return cache[key];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* NetworkTableConnectionListenerAdapter.cpp
|
||||
*
|
||||
* Created on: Oct 17, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables/NetworkTableConnectionListenerAdapter.h"
|
||||
|
||||
|
||||
NetworkTableConnectionListenerAdapter::NetworkTableConnectionListenerAdapter(IRemote* _targetSource, IRemoteConnectionListener* _targetListener):
|
||||
targetSource(_targetSource), targetListener(_targetListener){}
|
||||
NetworkTableConnectionListenerAdapter::~NetworkTableConnectionListenerAdapter(){}
|
||||
|
||||
void NetworkTableConnectionListenerAdapter::Connected(IRemote* remote) {
|
||||
targetListener->Connected(targetSource);
|
||||
}
|
||||
|
||||
void NetworkTableConnectionListenerAdapter::Disconnected(IRemote* remote) {
|
||||
targetListener->Disconnected(targetSource);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* NetworkTableKeyListenerAdapter.cpp
|
||||
*
|
||||
* Created on: Oct 17, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables/NetworkTableKeyListenerAdapter.h"
|
||||
|
||||
|
||||
|
||||
NetworkTableKeyListenerAdapter::NetworkTableKeyListenerAdapter(std::string _relativeKey, std::string _fullKey, NetworkTable* _targetSource, ITableListener* _targetListener):
|
||||
relativeKey(_relativeKey), fullKey(_fullKey), targetSource(_targetSource), targetListener(_targetListener){}
|
||||
|
||||
NetworkTableKeyListenerAdapter::~NetworkTableKeyListenerAdapter(){}
|
||||
|
||||
void NetworkTableKeyListenerAdapter::ValueChanged(ITable* source, const std::string& key, EntryValue value, bool isNew) {
|
||||
if(key==fullKey){
|
||||
targetListener->ValueChanged(targetSource, relativeKey, value, isNew);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* NetworkTableListenerAdapter.cpp
|
||||
*
|
||||
* Created on: Oct 17, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables/NetworkTableListenerAdapter.h"
|
||||
#include "networktables/NetworkTable.h"
|
||||
|
||||
|
||||
|
||||
NetworkTableListenerAdapter::NetworkTableListenerAdapter(std::string _prefix, ITable* _targetSource, ITableListener* _targetListener) :
|
||||
prefix(_prefix), targetSource(_targetSource), targetListener(_targetListener){}
|
||||
|
||||
NetworkTableListenerAdapter::~NetworkTableListenerAdapter(){}
|
||||
|
||||
void NetworkTableListenerAdapter::ValueChanged(ITable* source, const std::string& key, EntryValue value, bool isNew) {//TODO use string cache
|
||||
if(key.compare(0,prefix.size(),prefix)==0){
|
||||
std::string relativeKey = key.substr(prefix.length());
|
||||
if(std::string::npos != relativeKey.find(NetworkTable::PATH_SEPARATOR_CHAR))
|
||||
return;
|
||||
targetListener->ValueChanged(targetSource, relativeKey, value, isNew);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* NetworkTableMode.cpp
|
||||
*
|
||||
* Created on: Oct 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "networktables2/thread/NTThreadManager.h"
|
||||
#include "networktables2/NetworkTableNode.h"
|
||||
#include "networktables2/server/NetworkTableServer.h"
|
||||
#include "networktables2/client/NetworkTableClient.h"
|
||||
#include "networktables2/stream/SocketServerStreamProvider.h"
|
||||
#include "networktables2/stream/SocketStreamFactory.h"
|
||||
#include "networktables/NetworkTableMode.h"
|
||||
|
||||
|
||||
NetworkTableServerMode NetworkTableMode::Server;
|
||||
NetworkTableClientMode NetworkTableMode::Client;
|
||||
|
||||
NetworkTableServerMode::NetworkTableServerMode(){}
|
||||
NetworkTableClientMode::NetworkTableClientMode(){}
|
||||
|
||||
static void deleteIOStreamProvider(void* ptr){
|
||||
delete (IOStreamProvider*)ptr;
|
||||
}
|
||||
static void deleteIOStreamFactory(void* ptr){
|
||||
delete (IOStreamFactory*)ptr;
|
||||
}
|
||||
|
||||
NetworkTableNode* NetworkTableServerMode::CreateNode(const char* ipAddress, int port, NTThreadManager& threadManager, void*& streamFactory_out, StreamDeleter& streamDeleter_out, NetworkTableEntryTypeManager*& typeManager_out){
|
||||
IOStreamProvider* streamProvider = new SocketServerStreamProvider(port);
|
||||
streamFactory_out = streamProvider;
|
||||
typeManager_out = new NetworkTableEntryTypeManager();
|
||||
streamDeleter_out = deleteIOStreamFactory;
|
||||
return new NetworkTableServer(*streamProvider, *typeManager_out, threadManager);
|
||||
}
|
||||
NetworkTableNode* NetworkTableClientMode::CreateNode(const char* ipAddress, int port, NTThreadManager& threadManager, void*& streamFactory_out, StreamDeleter& streamDeleter_out, NetworkTableEntryTypeManager*& typeManager_out){
|
||||
IOStreamFactory* streamFactory = new SocketStreamFactory(ipAddress, port);
|
||||
streamFactory_out = streamFactory;
|
||||
typeManager_out = new NetworkTableEntryTypeManager();
|
||||
streamDeleter_out = deleteIOStreamProvider;
|
||||
return new NetworkTableClient(*streamFactory, *typeManager_out, threadManager);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "tables/ITableProvider.h"
|
||||
#include "networktables2/NetworkTableNode.h"
|
||||
#include "networktables/NetworkTable.h"
|
||||
|
||||
|
||||
#include "networktables/NetworkTableProvider.h"
|
||||
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
NetworkTableProvider::NetworkTableProvider(NetworkTableNode& _node) : node(_node){}
|
||||
NetworkTableProvider::~NetworkTableProvider(){
|
||||
while(tables.size()>0){
|
||||
map<std::string, NetworkTable*>::iterator it = tables.begin();
|
||||
delete it->second;
|
||||
tables.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
ITable* NetworkTableProvider::GetRootTable(){
|
||||
return GetTable("");
|
||||
}
|
||||
|
||||
ITable* NetworkTableProvider::GetTable(std::string key){
|
||||
if(tables.find(key) != tables.end())
|
||||
{
|
||||
return tables[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
NetworkTable* table = new NetworkTable(key, *this);
|
||||
tables[key] = table;
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* NetworkTableSubListenerAdapter.cpp
|
||||
*
|
||||
* Created on: Oct 17, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables/NetworkTableSubListenerAdapter.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new adapter
|
||||
* @param prefix the prefix of the current table
|
||||
* @param targetSource the source that events passed to the target listener will appear to come from
|
||||
* @param targetListener the listener where events are forwarded to
|
||||
*/
|
||||
NetworkTableSubListenerAdapter::NetworkTableSubListenerAdapter(std::string& _prefix, NetworkTable* _targetSource, ITableListener* _targetListener):
|
||||
prefix(_prefix), targetSource(_targetSource), targetListener(_targetListener){}
|
||||
|
||||
NetworkTableSubListenerAdapter::~NetworkTableSubListenerAdapter(){}
|
||||
|
||||
void NetworkTableSubListenerAdapter::ValueChanged(ITable* source, const std::string& key, EntryValue value, bool isNew) {//TODO use string cache
|
||||
if(key.compare(0,prefix.size(),prefix)==0){
|
||||
std::string relativeKey = key.substr(prefix.length()+1);
|
||||
int endSubTable = -1;//TODO implement sub table listening better
|
||||
for(unsigned int i = 0; i<relativeKey.length(); ++i){
|
||||
if(relativeKey.at(i)==NetworkTable::PATH_SEPARATOR_CHAR){//is sub table
|
||||
endSubTable = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(endSubTable!=-1){
|
||||
std::string subTableKey = relativeKey.substr(0, endSubTable);
|
||||
if(notifiedTables.find(subTableKey)==notifiedTables.end()){
|
||||
notifiedTables.insert(subTableKey);
|
||||
EntryValue eValue;
|
||||
eValue.ptr = targetSource->GetSubTable(subTableKey);
|
||||
targetListener->ValueChanged(targetSource, subTableKey, eValue, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* AbstractNetworkTableEntryStore.cpp
|
||||
*
|
||||
* Created on: Sep 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/AbstractNetworkTableEntryStore.h"
|
||||
#include "networktables2/TableKeyExistsWithDifferentTypeException.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
AbstractNetworkTableEntryStore::AbstractNetworkTableEntryStore(TableListenerManager& lstnManager):
|
||||
listenerManager(lstnManager){
|
||||
}
|
||||
|
||||
AbstractNetworkTableEntryStore::~AbstractNetworkTableEntryStore(){
|
||||
LOCK.take();
|
||||
std::map<std::string, NetworkTableEntry*>::iterator itr;
|
||||
for(itr = namedEntries.begin(); itr != namedEntries.end();){
|
||||
delete itr->second;
|
||||
namedEntries.erase(itr++);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an entry based on it's name
|
||||
* @param name the name of the entry to look for
|
||||
* @return the entry or null if the entry does not exist
|
||||
*/
|
||||
NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(std::string& name){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::map<std::string, NetworkTableEntry*>::iterator value_itr = namedEntries.find(name);
|
||||
if(value_itr != namedEntries.end()) {
|
||||
return value_itr->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(EntryId entryId){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
|
||||
std::map<EntryId, NetworkTableEntry*>::iterator value_itr = idEntries.find(entryId);
|
||||
if(value_itr != idEntries.end()) {
|
||||
return value_itr->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string>* AbstractNetworkTableEntryStore::keys(){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::vector<std::string>* keys = new std::vector<std::string>();
|
||||
std::map<std::string, NetworkTableEntry*>::iterator itr;
|
||||
|
||||
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
|
||||
{
|
||||
std::string key = (*itr).first;
|
||||
keys->push_back(key);
|
||||
}
|
||||
|
||||
return (keys);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all entries
|
||||
* NOTE: This method should not be used with applications which cache entries which would lead to unknown results
|
||||
* This method is for use in testing only
|
||||
*/
|
||||
void AbstractNetworkTableEntryStore::clearEntries(){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
namedEntries.clear();
|
||||
idEntries.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the id's of all entries
|
||||
*/
|
||||
void AbstractNetworkTableEntryStore::clearIds(){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::map<std::string, NetworkTableEntry*>::iterator itr;
|
||||
idEntries.clear();
|
||||
|
||||
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
|
||||
{
|
||||
((NetworkTableEntry*)(*itr).second)->ClearId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractNetworkTableEntryStore::SetOutgoingReceiver(OutgoingEntryReceiver* receiver){
|
||||
outgoingReceiver = receiver;
|
||||
}
|
||||
|
||||
void AbstractNetworkTableEntryStore::SetIncomingReceiver(OutgoingEntryReceiver* receiver){
|
||||
incomingReceiver = receiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given value under the given name and queues it for
|
||||
* transmission to the server.
|
||||
*
|
||||
* @param name The name under which to store the given value.
|
||||
* @param type The type of the given value.
|
||||
* @param value The value to store.
|
||||
* @throws TableKeyExistsWithDifferentTypeException Thrown if an
|
||||
* entry already exists with the given name and is of a different type.
|
||||
*/
|
||||
void AbstractNetworkTableEntryStore::PutOutgoing(std::string& name, NetworkTableEntryType* type, EntryValue value){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::map<std::string, NetworkTableEntry*>::iterator index = namedEntries.find(name);
|
||||
NetworkTableEntry* tableEntry;
|
||||
if(index == namedEntries.end())//if the name does not exist in the current entries
|
||||
{
|
||||
tableEntry = new NetworkTableEntry(name, type, value);
|
||||
if(addEntry(tableEntry))
|
||||
{
|
||||
tableEntry->FireListener(listenerManager);
|
||||
outgoingReceiver->offerOutgoingAssignment(tableEntry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tableEntry = index->second;
|
||||
if(tableEntry->GetType()->id != type->id){
|
||||
throw TableKeyExistsWithDifferentTypeException(name, tableEntry->GetType());
|
||||
}
|
||||
|
||||
EntryValue oldValue = tableEntry->GetValue();
|
||||
if(!type->areEqual(value, oldValue)){
|
||||
if(updateEntry(tableEntry, (SequenceNumber)(tableEntry->GetSequenceNumber() + 1), value)){
|
||||
outgoingReceiver->offerOutgoingUpdate(tableEntry);
|
||||
}
|
||||
|
||||
tableEntry->FireListener(listenerManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractNetworkTableEntryStore::PutOutgoing(NetworkTableEntry* tableEntry, EntryValue value){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
NetworkTableEntryType* type = tableEntry->GetType();
|
||||
EntryValue oldValue = tableEntry->GetValue();
|
||||
if(!type->areEqual(value, oldValue)){
|
||||
if(updateEntry(tableEntry, (SequenceNumber)(tableEntry->GetSequenceNumber() + 1), value)){
|
||||
outgoingReceiver->offerOutgoingUpdate(tableEntry);
|
||||
}
|
||||
|
||||
tableEntry->FireListener(listenerManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractNetworkTableEntryStore::offerIncomingAssignment(NetworkTableEntry* entry){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::map<std::string, NetworkTableEntry*>::iterator itr = namedEntries.find(entry->name);
|
||||
NetworkTableEntry* tableEntry;
|
||||
if(addEntry(entry)){
|
||||
if(itr != namedEntries.end()){
|
||||
tableEntry = itr->second;
|
||||
}
|
||||
else{
|
||||
tableEntry = entry;
|
||||
}
|
||||
|
||||
tableEntry->FireListener(listenerManager);//if we didnt have a pointer, then the copy of the version in the list would call this method, however with the pointer we are updating the version in the list
|
||||
incomingReceiver->offerOutgoingAssignment(tableEntry);
|
||||
}
|
||||
else
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractNetworkTableEntryStore::offerIncomingUpdate(NetworkTableEntry* entry, SequenceNumber squenceNumber, EntryValue value){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
if(updateEntry(entry, squenceNumber, value)){
|
||||
entry->FireListener(listenerManager);
|
||||
incomingReceiver->offerOutgoingUpdate(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to say that a listener should notify the listener manager of all of the entries
|
||||
* @param listener
|
||||
* @param table
|
||||
*/
|
||||
void AbstractNetworkTableEntryStore::notifyEntries(ITable* table, ITableListener* listener){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::map<std::string, NetworkTableEntry*>::iterator itr;
|
||||
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
|
||||
{
|
||||
NetworkTableEntry* entry = itr->second;
|
||||
listener->ValueChanged(table, itr->first, entry->GetValue(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "networktables2/NetworkTableEntry.h"
|
||||
#include "networktables2/AbstractNetworkTableEntryStore.h"
|
||||
|
||||
|
||||
NetworkTableEntry::NetworkTableEntry(std::string& _name, NetworkTableEntryType* _type, EntryValue _value)
|
||||
: name(_name), type(_type){
|
||||
id = UNKNOWN_ID;
|
||||
sequenceNumber = 0;
|
||||
value = type->copyValue(_value);
|
||||
m_isNew = true;
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
NetworkTableEntry::NetworkTableEntry(EntryId _id, std::string& _name, SequenceNumber _sequenceNumber, NetworkTableEntryType* _type, EntryValue _value)
|
||||
:name(_name), type(_type){
|
||||
id = _id;
|
||||
sequenceNumber = _sequenceNumber;
|
||||
value = type->copyValue(_value);
|
||||
m_isNew = true;
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
NetworkTableEntry::~NetworkTableEntry(){
|
||||
type->deleteValue(value);
|
||||
}
|
||||
|
||||
EntryId NetworkTableEntry::GetId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
EntryValue NetworkTableEntry::GetValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
NetworkTableEntryType* NetworkTableEntry::GetType(){
|
||||
return type;
|
||||
}
|
||||
|
||||
bool NetworkTableEntry::PutValue(SequenceNumber newSequenceNumber, EntryValue newValue) {
|
||||
if( (sequenceNumber < newSequenceNumber && newSequenceNumber - sequenceNumber < HALF_OF_SEQUENCE_NUMBERS)
|
||||
|| (sequenceNumber > newSequenceNumber && sequenceNumber - newSequenceNumber > HALF_OF_SEQUENCE_NUMBERS) ){
|
||||
EntryValue newValueCopy = type->copyValue(newValue);
|
||||
type->deleteValue(value);
|
||||
value = newValueCopy;
|
||||
sequenceNumber = newSequenceNumber;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* force a value and new sequence number upon an entry
|
||||
* @param newSequenceNumber
|
||||
* @param newValue
|
||||
*/
|
||||
void NetworkTableEntry::ForcePut(SequenceNumber newSequenceNumber, EntryValue newValue) {
|
||||
EntryValue newValueCopy = type->copyValue(newValue);
|
||||
type->deleteValue(value);
|
||||
value = newValueCopy;
|
||||
sequenceNumber = newSequenceNumber;
|
||||
}
|
||||
/**
|
||||
* force a value and new sequence number upon an entry, Will also set the type of the entry
|
||||
* @param newSequenceNumber
|
||||
* @param type
|
||||
* @param newValue
|
||||
*/
|
||||
void NetworkTableEntry::ForcePut(SequenceNumber newSequenceNumber, NetworkTableEntryType* newType, EntryValue newValue) {
|
||||
type->deleteValue(value);
|
||||
type = newType;
|
||||
value = newType->copyValue(newValue);
|
||||
sequenceNumber = newSequenceNumber;
|
||||
}
|
||||
|
||||
|
||||
void NetworkTableEntry::MakeDirty() {
|
||||
m_isDirty = true;
|
||||
}
|
||||
void NetworkTableEntry::MakeClean() {
|
||||
m_isDirty = false;
|
||||
}
|
||||
bool NetworkTableEntry::IsDirty(){
|
||||
return m_isDirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the value of the entry over the output stream
|
||||
* @param os
|
||||
* @throws IOException
|
||||
*/
|
||||
void NetworkTableEntry::SendValue(DataIOStream& iostream){
|
||||
type->sendValue(value, iostream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current sequence number of the entry
|
||||
*/
|
||||
SequenceNumber NetworkTableEntry::GetSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
/**
|
||||
* Sets the id of the entry
|
||||
* @param id the id of the entry
|
||||
* @throws IllegalStateException if the entry already has a known id
|
||||
*/
|
||||
void NetworkTableEntry::SetId(EntryId _id){
|
||||
if(id!=UNKNOWN_ID)
|
||||
throw IllegalStateException("Cannot set the Id of a table entry that already has a valid id");
|
||||
id = _id;
|
||||
}
|
||||
/**
|
||||
* clear the id of the entry to unknown
|
||||
*/
|
||||
void NetworkTableEntry::ClearId() {
|
||||
id = UNKNOWN_ID;
|
||||
}
|
||||
|
||||
void NetworkTableEntry::Send(NetworkTableConnection& connection) {
|
||||
connection.sendEntryAssignment(*this);
|
||||
}
|
||||
void NetworkTableEntry::FireListener(TableListenerManager& listenerManager) {
|
||||
listenerManager.FireTableListeners(name, value, m_isNew);
|
||||
m_isNew = false;
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* NetworkTableNode.cpp
|
||||
*
|
||||
* Created on: Sep 24, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/NetworkTableNode.h"
|
||||
#include "networktables2/TableKeyExistsWithDifferentTypeException.h"
|
||||
#include "networktables2/type/DefaultEntryTypes.h"
|
||||
#include "tables/TableKeyNotDefinedException.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
|
||||
NetworkTableNode::NetworkTableNode(AbstractNetworkTableEntryStore& _entryStore):
|
||||
entryStore(_entryStore){
|
||||
}
|
||||
|
||||
NetworkTableNode::~NetworkTableNode(){}
|
||||
|
||||
AbstractNetworkTableEntryStore& NetworkTableNode::GetEntryStore(){
|
||||
return entryStore;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NetworkTableNode::PutBoolean(std::string& name, bool value){
|
||||
EntryValue eValue;
|
||||
eValue.b = value;
|
||||
PutValue(name, &DefaultEntryTypes::BOOLEAN, eValue);
|
||||
}
|
||||
bool NetworkTableNode::GetBoolean(std::string& name){
|
||||
NetworkTableEntry* entry = entryStore.GetEntry(name);
|
||||
if(entry==NULL)
|
||||
throw TableKeyNotDefinedException(name);
|
||||
return entry->GetValue().b;
|
||||
}
|
||||
|
||||
void NetworkTableNode::PutDouble(std::string& name, double value){
|
||||
EntryValue eValue;
|
||||
eValue.f = value;
|
||||
PutValue(name, &DefaultEntryTypes::DOUBLE, eValue);
|
||||
}
|
||||
double NetworkTableNode::GetDouble(std::string& name){
|
||||
NetworkTableEntry* entry = entryStore.GetEntry(name);
|
||||
if(entry==NULL)
|
||||
throw TableKeyNotDefinedException(name);
|
||||
return entry->GetValue().f;
|
||||
}
|
||||
|
||||
void NetworkTableNode::PutString(std::string& name, std::string& value){
|
||||
EntryValue eValue;
|
||||
eValue.ptr = &value;
|
||||
PutValue(name, &DefaultEntryTypes::STRING, eValue);
|
||||
}
|
||||
std::string& NetworkTableNode::GetString(std::string& name) {
|
||||
NetworkTableEntry* entry = entryStore.GetEntry(name);
|
||||
if(entry==NULL)
|
||||
throw TableKeyNotDefinedException(name);
|
||||
return *(std::string*)(entry->GetValue().ptr);
|
||||
}
|
||||
|
||||
void NetworkTableNode::PutComplex(std::string& name, ComplexData& value){
|
||||
EntryValue eValue;
|
||||
eValue.ptr = &value;
|
||||
PutValue(name, &value.GetType(), eValue);
|
||||
}
|
||||
|
||||
void NetworkTableNode::retrieveValue(std::string& name, ComplexData& externalData){
|
||||
{
|
||||
NTSynchronized sync(entryStore.LOCK);
|
||||
NetworkTableEntry* entry = entryStore.GetEntry(name);
|
||||
if(entry==NULL)
|
||||
throw TableKeyNotDefinedException(name);
|
||||
NetworkTableEntryType* entryType = entry->GetType();
|
||||
if(!entryType->isComplex())
|
||||
throw TableKeyExistsWithDifferentTypeException(name, entryType, "Is not a complex data type");
|
||||
ComplexEntryType* complexType = (ComplexEntryType*)entryType;
|
||||
complexType->exportValue(name, entry->GetValue(), externalData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NetworkTableNode::PutValue(std::string& name, NetworkTableEntryType* type, EntryValue value){
|
||||
if(type->isComplex()){
|
||||
{
|
||||
NTSynchronized sync(entryStore.LOCK);
|
||||
ComplexData* complexData = (ComplexData*)value.ptr;
|
||||
ComplexEntryType* entryType = (ComplexEntryType*)type;
|
||||
NetworkTableEntry* entry = entryStore.GetEntry(name);
|
||||
if(entry!=NULL)
|
||||
entryStore.PutOutgoing(entry, entryType->internalizeValue(entry->name, *complexData, entry->GetValue()));
|
||||
else{
|
||||
EntryValue nullValue = {0};
|
||||
EntryValue entryValue = entryType->internalizeValue(name, *complexData, nullValue);
|
||||
entryStore.PutOutgoing(name, type, entryValue);//TODO the entry gets copied when creating the entry should make lifecycle cleaner
|
||||
type->deleteValue(entryValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
entryStore.PutOutgoing(name, type, value);
|
||||
}
|
||||
|
||||
void NetworkTableNode::PutValue(NetworkTableEntry* entry, EntryValue value){
|
||||
if(entry->GetType()->isComplex()){
|
||||
{
|
||||
NTSynchronized sync(entryStore.LOCK);
|
||||
ComplexEntryType* entryType = (ComplexEntryType*)entry->GetType();
|
||||
|
||||
entryStore.PutOutgoing(entry, entryType->internalizeValue(entry->name, *(ComplexData*)value.ptr, entry->GetValue()));
|
||||
}
|
||||
}
|
||||
else
|
||||
entryStore.PutOutgoing(entry, value);
|
||||
}
|
||||
|
||||
EntryValue NetworkTableNode::GetValue(std::string& name){//TODO don't allow get of complex types
|
||||
{
|
||||
NTSynchronized sync(entryStore.LOCK);
|
||||
NetworkTableEntry* entry = entryStore.GetEntry(name);
|
||||
if(entry==NULL)
|
||||
throw TableKeyNotDefinedException(name);
|
||||
return entry->GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool NetworkTableNode::ContainsKey(std::string& key){
|
||||
return entryStore.GetEntry(key)!=NULL;
|
||||
}
|
||||
|
||||
void NetworkTableNode::AddConnectionListener(IRemoteConnectionListener* listener, bool immediateNotify) {
|
||||
remoteListeners.push_back(listener);
|
||||
if(IsConnected())
|
||||
listener->Connected(this);
|
||||
else
|
||||
listener->Disconnected(this);
|
||||
}
|
||||
void NetworkTableNode::RemoveConnectionListener(IRemoteConnectionListener* listener) {
|
||||
std::vector<IRemoteConnectionListener*>::iterator listenerPosition = std::find(remoteListeners.begin(), remoteListeners.end(), listener);
|
||||
if(listenerPosition!=remoteListeners.end())
|
||||
remoteListeners.erase(listenerPosition);
|
||||
}
|
||||
void NetworkTableNode::FireConnectedEvent(){
|
||||
for(unsigned int i = 0; i<remoteListeners.size(); ++i)
|
||||
remoteListeners.at(i)->Connected(this);
|
||||
}
|
||||
void NetworkTableNode::FireDisconnectedEvent(){
|
||||
for(unsigned int i = 0; i<remoteListeners.size(); ++i)
|
||||
remoteListeners.at(i)->Disconnected(this);
|
||||
}
|
||||
|
||||
|
||||
void NetworkTableNode::AddTableListener(ITableListener* listener, bool immediateNotify) {
|
||||
tableListeners.push_back(listener);
|
||||
if(immediateNotify)
|
||||
entryStore.notifyEntries(NULL, listener);
|
||||
}
|
||||
void NetworkTableNode::RemoveTableListener(ITableListener* listener) {
|
||||
std::vector<ITableListener*>::iterator listenerPosition = std::find(tableListeners.begin(), tableListeners.end(), listener);
|
||||
if(listenerPosition!=tableListeners.end())
|
||||
tableListeners.erase(listenerPosition);
|
||||
}
|
||||
void NetworkTableNode::FireTableListeners(std::string& key, EntryValue value, bool isNew){
|
||||
for(unsigned int i = 0; i<tableListeners.size(); ++i)
|
||||
tableListeners.at(i)->ValueChanged(NULL, key, value, isNew);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* OutgoingEntryReciever.cpp
|
||||
*
|
||||
* Created on: Nov 3, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/OutgoingEntryReceiver.h"
|
||||
|
||||
OutgoingEntryReceiver_NULL_t OutgoingEntryReceiver_NULL;
|
||||
|
||||
void OutgoingEntryReceiver_NULL_t::offerOutgoingAssignment(NetworkTableEntry* entry){}
|
||||
void OutgoingEntryReceiver_NULL_t::offerOutgoingUpdate(NetworkTableEntry* entry){}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* TableKeyExistsWithDifferentKeyException.cpp
|
||||
*
|
||||
* Created on: Sep 22, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/TableKeyExistsWithDifferentTypeException.h"
|
||||
|
||||
|
||||
|
||||
TableKeyExistsWithDifferentTypeException::TableKeyExistsWithDifferentTypeException(const std::string, NetworkTableEntryType* existingType) {
|
||||
//TODO construct string this(existingKey, existingType, "");
|
||||
}
|
||||
|
||||
TableKeyExistsWithDifferentTypeException::TableKeyExistsWithDifferentTypeException(const std::string, NetworkTableEntryType* existingType, const char* message) {
|
||||
//TODO construct string super("Illegal put - key '" + existingKey + "' exists with type '" + existingType + "'. "+message);
|
||||
}
|
||||
|
||||
TableKeyExistsWithDifferentTypeException::~TableKeyExistsWithDifferentTypeException() throw (){
|
||||
//TODO delete message
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* TransactionDirtier.cpp
|
||||
*
|
||||
* Created on: Sep 24, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/TransactionDirtier.h"
|
||||
|
||||
|
||||
|
||||
TransactionDirtier::TransactionDirtier(OutgoingEntryReceiver& _continuingReceiver) : continuingReceiver(_continuingReceiver){
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TransactionDirtier::offerOutgoingAssignment(NetworkTableEntry* entry) {
|
||||
if(entry->IsDirty())
|
||||
return;
|
||||
entry->MakeDirty();
|
||||
continuingReceiver.offerOutgoingAssignment(entry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void TransactionDirtier::offerOutgoingUpdate(NetworkTableEntry* entry) {
|
||||
if(entry->IsDirty())
|
||||
return;
|
||||
entry->MakeDirty();
|
||||
continuingReceiver.offerOutgoingUpdate(entry);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* WriteManager.cpp
|
||||
*
|
||||
* Created on: Sep 25, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/WriteManager.h"
|
||||
#include "networktables2/util/System.h"
|
||||
#include "networktables2/AbstractNetworkTableEntryStore.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
WriteManager::WriteManager(FlushableOutgoingEntryReceiver& _receiver, NTThreadManager& _threadManager, AbstractNetworkTableEntryStore& _entryStore, unsigned long _keepAliveDelay)
|
||||
: receiver(_receiver), threadManager(_threadManager), entryStore(_entryStore), keepAliveDelay(_keepAliveDelay){
|
||||
|
||||
thread = NULL;
|
||||
lastWrite = 0;
|
||||
|
||||
incomingAssignmentQueue = new std::queue<NetworkTableEntry*>();
|
||||
incomingUpdateQueue = new std::queue<NetworkTableEntry*>();
|
||||
outgoingAssignmentQueue = new std::queue<NetworkTableEntry*>();
|
||||
outgoingUpdateQueue = new std::queue<NetworkTableEntry*>();
|
||||
}
|
||||
|
||||
WriteManager::~WriteManager(){
|
||||
stop();
|
||||
|
||||
//Note: this must occur after stop() to avoid deadlock
|
||||
transactionsLock.take();
|
||||
|
||||
delete incomingAssignmentQueue;
|
||||
delete incomingUpdateQueue;
|
||||
delete outgoingAssignmentQueue;
|
||||
delete outgoingUpdateQueue;
|
||||
}
|
||||
|
||||
void WriteManager::start(){
|
||||
if(thread!=NULL)
|
||||
stop();
|
||||
lastWrite = currentTimeMillis();
|
||||
thread = threadManager.newBlockingPeriodicThread(this, "Write Manager Thread");
|
||||
}
|
||||
|
||||
void WriteManager::stop(){
|
||||
if(thread!=NULL){
|
||||
thread->stop();
|
||||
delete thread;
|
||||
thread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WriteManager::offerOutgoingAssignment(NetworkTableEntry* entry) {
|
||||
{
|
||||
NTSynchronized sync(transactionsLock);
|
||||
((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->push(entry);
|
||||
|
||||
if(((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->size()>=queueSize){
|
||||
run();
|
||||
writeWarning("assignment queue overflowed. decrease the rate at which you create new entries or increase the write buffer size");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WriteManager::offerOutgoingUpdate(NetworkTableEntry* entry) {
|
||||
{
|
||||
NTSynchronized sync(transactionsLock);
|
||||
((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->push(entry);
|
||||
if(((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->size()>=queueSize){
|
||||
run();
|
||||
writeWarning("update queue overflowed. decrease the rate at which you update entries or increase the write buffer size");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WriteManager::run() {
|
||||
{
|
||||
NTSynchronized sync(transactionsLock);
|
||||
//swap the assignment and update queue
|
||||
volatile std::queue<NetworkTableEntry*>* tmp = incomingAssignmentQueue;
|
||||
incomingAssignmentQueue = outgoingAssignmentQueue;
|
||||
outgoingAssignmentQueue = tmp;
|
||||
|
||||
tmp = incomingUpdateQueue;
|
||||
incomingUpdateQueue = outgoingUpdateQueue;
|
||||
outgoingUpdateQueue = tmp;
|
||||
}
|
||||
|
||||
bool wrote = false;
|
||||
NetworkTableEntry* entry;
|
||||
|
||||
while(!((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->empty()){
|
||||
entry = ((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->front();
|
||||
((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->pop();
|
||||
{
|
||||
NTSynchronized sync(entryStore.LOCK);
|
||||
entry->MakeClean();
|
||||
wrote = true;
|
||||
receiver.offerOutgoingAssignment(entry);
|
||||
}
|
||||
}
|
||||
|
||||
while(!((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->empty()){
|
||||
entry = ((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->front();
|
||||
((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->pop();
|
||||
{
|
||||
NTSynchronized sync(entryStore.LOCK);
|
||||
entry->MakeClean();
|
||||
wrote = true;
|
||||
receiver.offerOutgoingUpdate(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(wrote){
|
||||
receiver.flush();
|
||||
lastWrite = currentTimeMillis();
|
||||
}
|
||||
else if(currentTimeMillis()-lastWrite>keepAliveDelay)
|
||||
receiver.ensureAlive();
|
||||
|
||||
sleep_ms(20);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* ClientConnectionAdapter.cpp
|
||||
*
|
||||
* Created on: Nov 2, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/client/ClientConnectionAdapter.h"
|
||||
#include "networktables2/util/System.h"
|
||||
|
||||
void ClientConnectionAdapter::gotoState(ClientConnectionState* newState){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
if(connectionState!=newState){
|
||||
fprintf(stdout, "[NT] %p entered connection state: %s\n", (void*)this, newState->toString());
|
||||
fflush(stdout);
|
||||
if(newState==&ClientConnectionState::IN_SYNC_WITH_SERVER)
|
||||
connectionListenerManager.FireConnectedEvent();
|
||||
if(connectionState==&ClientConnectionState::IN_SYNC_WITH_SERVER)
|
||||
connectionListenerManager.FireDisconnectedEvent();
|
||||
//TODO find better way to manage memory leak
|
||||
ClientConnectionState_Error *temp=dynamic_cast<ClientConnectionState_Error *>(connectionState);
|
||||
connectionState = newState;
|
||||
if (temp)
|
||||
delete temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return the state of the connection
|
||||
*/
|
||||
ClientConnectionState* ClientConnectionAdapter::getConnectionState(){
|
||||
return connectionState;
|
||||
}
|
||||
/**
|
||||
* @return if the client is connected to the server
|
||||
*/
|
||||
bool ClientConnectionAdapter::isConnected() {
|
||||
return getConnectionState()==&ClientConnectionState::IN_SYNC_WITH_SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClientConnectionAdapter
|
||||
* @param entryStore
|
||||
* @param threadManager
|
||||
* @param streamFactory
|
||||
* @param transactionPool
|
||||
* @param connectionListenerManager
|
||||
*/
|
||||
ClientConnectionAdapter::ClientConnectionAdapter(ClientNetworkTableEntryStore& _entryStore, NTThreadManager& _threadManager, IOStreamFactory& _streamFactory, ClientConnectionListenerManager& _connectionListenerManager, NetworkTableEntryTypeManager& _typeManager):
|
||||
entryStore(_entryStore),
|
||||
streamFactory(_streamFactory),
|
||||
threadManager(_threadManager),
|
||||
connectionListenerManager(_connectionListenerManager),
|
||||
typeManager(_typeManager),
|
||||
readThread(NULL),
|
||||
monitor(NULL),
|
||||
connection(NULL){
|
||||
connectionState = &ClientConnectionState::DISCONNECTED_FROM_SERVER;
|
||||
}
|
||||
ClientConnectionAdapter::~ClientConnectionAdapter()
|
||||
{
|
||||
if(readThread!=NULL)
|
||||
readThread->stop();
|
||||
if (connection)
|
||||
connection->close();
|
||||
if(readThread!=NULL)
|
||||
{
|
||||
delete readThread;
|
||||
readThread = NULL;
|
||||
}
|
||||
if(monitor!=NULL)
|
||||
{
|
||||
delete monitor;
|
||||
monitor = NULL;
|
||||
}
|
||||
close();
|
||||
if(connection!=NULL){
|
||||
delete connection;
|
||||
connection = NULL;
|
||||
}
|
||||
|
||||
//TODO find better way to manage memory leak
|
||||
ClientConnectionState_Error *temp=dynamic_cast<ClientConnectionState_Error *>(connectionState);
|
||||
if (temp)
|
||||
{
|
||||
delete temp;
|
||||
connectionState=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Connection management
|
||||
*/
|
||||
/**
|
||||
* Reconnect the client to the server (even if the client is not currently connected)
|
||||
*/
|
||||
void ClientConnectionAdapter::reconnect() {
|
||||
//This is in reconnect so that the entry store doesn't have to be valid when this object is deleted
|
||||
//Note: clearIds() cannot be in a LOCK critical section
|
||||
entryStore.clearIds();
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
close();//close the existing stream and monitor thread if needed
|
||||
try{
|
||||
IOStream* stream = streamFactory.createStream();
|
||||
if(stream==NULL)
|
||||
return;
|
||||
if (!connection)
|
||||
connection = new NetworkTableConnection(stream, typeManager);
|
||||
else
|
||||
connection->SetIOStream(stream);
|
||||
m_IsConnectionClosed=false;
|
||||
if (!monitor)
|
||||
monitor = new ConnectionMonitorThread(*this, *connection);
|
||||
if (!readThread)
|
||||
readThread = threadManager.newBlockingPeriodicThread(monitor, "Client Connection Reader Thread");
|
||||
connection->sendClientHello();
|
||||
gotoState(&ClientConnectionState::CONNECTED_TO_SERVER);
|
||||
} catch(IOException& e){
|
||||
close();//make sure to clean everything up if we fail to connect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the client connection
|
||||
*/
|
||||
void ClientConnectionAdapter::close() {
|
||||
close(&ClientConnectionState::DISCONNECTED_FROM_SERVER);
|
||||
}
|
||||
/**
|
||||
* Close the connection to the server and enter the given state
|
||||
* @param newState
|
||||
*/
|
||||
void ClientConnectionAdapter::close(ClientConnectionState* newState) {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
gotoState(newState);
|
||||
//Disconnect the socket
|
||||
if(connection!=NULL)
|
||||
{
|
||||
connection->close();
|
||||
connection->SetIOStream(NULL); //disconnect the table connection from the IO stream
|
||||
}
|
||||
m_IsConnectionClosed=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClientConnectionAdapter::badMessage(BadMessageException& e) {
|
||||
close(new ClientConnectionState_Error(e));
|
||||
sleep_ms(33); //avoid busy wait
|
||||
}
|
||||
|
||||
void ClientConnectionAdapter::ioException(IOException& e) {
|
||||
if(connectionState!=&ClientConnectionState::DISCONNECTED_FROM_SERVER)//will get io exception when on read thread connection is closed
|
||||
{
|
||||
reconnect();
|
||||
sleep_ms(500);
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep_ms(33); //avoid busy wait
|
||||
}
|
||||
}
|
||||
|
||||
NetworkTableEntry* ClientConnectionAdapter::GetEntry(EntryId id) {
|
||||
return entryStore.GetEntry(id);
|
||||
}
|
||||
|
||||
|
||||
bool ClientConnectionAdapter::keepAlive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientConnectionAdapter::clientHello(ProtocolVersion protocolRevision) {
|
||||
throw BadMessageException("A client should not receive a client hello message");
|
||||
}
|
||||
|
||||
void ClientConnectionAdapter::protocolVersionUnsupported(ProtocolVersion protocolRevision) {
|
||||
close();
|
||||
gotoState(new ClientConnectionState_ProtocolUnsuppotedByServer(protocolRevision));
|
||||
}
|
||||
|
||||
void ClientConnectionAdapter::serverHelloComplete() {
|
||||
if (connectionState==&ClientConnectionState::CONNECTED_TO_SERVER) {
|
||||
try {
|
||||
gotoState(&ClientConnectionState::IN_SYNC_WITH_SERVER);
|
||||
entryStore.sendUnknownEntries(*connection);
|
||||
} catch (IOException& e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw BadMessageException("A client should only receive a server hello complete once and only after it has connected to the server");
|
||||
}
|
||||
|
||||
|
||||
void ClientConnectionAdapter::offerIncomingAssignment(NetworkTableEntry* entry) {
|
||||
entryStore.offerIncomingAssignment(entry);
|
||||
}
|
||||
void ClientConnectionAdapter::offerIncomingUpdate(NetworkTableEntry* entry, SequenceNumber sequenceNumber, EntryValue value) {
|
||||
entryStore.offerIncomingUpdate(entry, sequenceNumber, value);
|
||||
}
|
||||
|
||||
void ClientConnectionAdapter::offerOutgoingAssignment(NetworkTableEntry* entry) {
|
||||
try {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
if(connection!=NULL && connectionState==&ClientConnectionState::IN_SYNC_WITH_SERVER)
|
||||
connection->sendEntryAssignment(*entry);
|
||||
}
|
||||
} catch(IOException& e){
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientConnectionAdapter::offerOutgoingUpdate(NetworkTableEntry* entry) {
|
||||
try {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
if(connection!=NULL && connectionState==&ClientConnectionState::IN_SYNC_WITH_SERVER)
|
||||
connection->sendEntryUpdate(*entry);
|
||||
}
|
||||
} catch(IOException& e){
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
void ClientConnectionAdapter::flush() {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
if(connection!=NULL) {
|
||||
try {
|
||||
connection->flush();
|
||||
} catch (IOException& e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void ClientConnectionAdapter::ensureAlive() {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
if ((connection!=NULL)&&(!m_IsConnectionClosed)) {
|
||||
try {
|
||||
connection->sendKeepAlive();
|
||||
} catch (IOException& e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
reconnect();//try to reconnect if not connected
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* ClientConnectionState.cpp
|
||||
*
|
||||
* Created on: Nov 2, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
#include "networktables2/client/ClientConnectionState.h"
|
||||
#ifndef _WRS_KERNEL
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
/**
|
||||
* indicates that the client is disconnected from the server
|
||||
*/
|
||||
ClientConnectionState ClientConnectionState::DISCONNECTED_FROM_SERVER("DISCONNECTED_FROM_SERVER");
|
||||
/**
|
||||
* indicates that the client is connected to the server but has not yet begun communication
|
||||
*/
|
||||
ClientConnectionState ClientConnectionState::CONNECTED_TO_SERVER("CONNECTED_TO_SERVER");
|
||||
/**
|
||||
* represents that the client has sent the hello to the server and is waiting for a response
|
||||
*/
|
||||
ClientConnectionState ClientConnectionState::SENT_HELLO_TO_SERVER("SENT_HELLO_TO_SERVER");
|
||||
/**
|
||||
* represents that the client is now in sync with the server
|
||||
*/
|
||||
ClientConnectionState ClientConnectionState::IN_SYNC_WITH_SERVER("IN_SYNC_WITH_SERVER");
|
||||
|
||||
|
||||
/**
|
||||
* Create a new protocol unsupported state
|
||||
* @param serverVersion
|
||||
*/
|
||||
ClientConnectionState_ProtocolUnsuppotedByServer::ClientConnectionState_ProtocolUnsuppotedByServer(ProtocolVersion _serverVersion):
|
||||
ClientConnectionState("PROTOCOL_UNSUPPORTED_BY_SERVER"),
|
||||
serverVersion(_serverVersion){}
|
||||
/**
|
||||
* @return the protocol version that the server reported it supports
|
||||
*/
|
||||
ProtocolVersion ClientConnectionState_ProtocolUnsuppotedByServer::getServerVersion(){
|
||||
return serverVersion;
|
||||
}
|
||||
const char* ClientConnectionState_ProtocolUnsuppotedByServer::toString(){
|
||||
return "PROTOCOL_UNSUPPORTED_BY_SERVER";
|
||||
//return "PROTOCOL_UNSUPPORTED_BY_SERVER: Server Version: 0x"+Integer.toHexString(serverVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new error state
|
||||
* @param e
|
||||
*/
|
||||
ClientConnectionState_Error::ClientConnectionState_Error(std::exception& _e):ClientConnectionState("CLIENT_ERROR"),e(_e){
|
||||
strcpy(msg, "CLIENT_ERROR: ");
|
||||
strcat(msg, e.what());
|
||||
}
|
||||
/**
|
||||
* @return the exception that caused the client to enter an error state
|
||||
*/
|
||||
std::exception& ClientConnectionState_Error::getException(){
|
||||
return e;
|
||||
}
|
||||
const char* ClientConnectionState_Error::toString(){
|
||||
return msg;
|
||||
//return "CLIENT_ERROR";
|
||||
//return "CLIENT_ERROR: "+e.getClass()+": "+e.getMessage();
|
||||
}
|
||||
|
||||
ClientConnectionState::ClientConnectionState(const char* _name){
|
||||
name = _name;
|
||||
}
|
||||
const char* ClientConnectionState::toString(){
|
||||
return name;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* ClientNetworkTableEntryStore.cpp
|
||||
*
|
||||
* Created on: Nov 2, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/client/ClientNetworkTableEntryStore.h"
|
||||
|
||||
/**
|
||||
* Create a new ClientNetworkTableEntryStore
|
||||
* @param transactionPool
|
||||
* @param listenerManager
|
||||
*/
|
||||
ClientNetworkTableEntryStore::ClientNetworkTableEntryStore(TableListenerManager& listenerManager): AbstractNetworkTableEntryStore(listenerManager) {}
|
||||
ClientNetworkTableEntryStore::~ClientNetworkTableEntryStore(){}
|
||||
|
||||
bool ClientNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry){
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
NetworkTableEntry* entry = (NetworkTableEntry*)namedEntries[newEntry->name];
|
||||
|
||||
if(entry!=NULL){
|
||||
if(entry->GetId()!=newEntry->GetId()){
|
||||
idEntries.erase(entry->GetId());
|
||||
if(newEntry->GetId()!=NetworkTableEntry::UNKNOWN_ID){
|
||||
entry->SetId(newEntry->GetId());
|
||||
idEntries[newEntry->GetId()] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
entry->ForcePut(newEntry->GetSequenceNumber(), newEntry->GetType(), newEntry->GetValue());
|
||||
}
|
||||
else{
|
||||
if(newEntry->GetId()!=NetworkTableEntry::UNKNOWN_ID)
|
||||
idEntries[newEntry->GetId()] = newEntry;
|
||||
namedEntries[newEntry->name] = newEntry;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientNetworkTableEntryStore::updateEntry(NetworkTableEntry* entry, SequenceNumber sequenceNumber, EntryValue value) {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
entry->ForcePut(sequenceNumber, value);
|
||||
if(entry->GetId()==NetworkTableEntry::UNKNOWN_ID){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send all unknown entries in the entry store to the given connection
|
||||
* @param connection
|
||||
* @throws IOException
|
||||
*/
|
||||
void ClientNetworkTableEntryStore::sendUnknownEntries(NetworkTableConnection& connection) {
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::map<std::string, NetworkTableEntry*>::iterator itr;
|
||||
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
|
||||
{
|
||||
NetworkTableEntry* entry = (*itr).second;
|
||||
if(entry->GetId()==NetworkTableEntry::UNKNOWN_ID)
|
||||
connection.sendEntryAssignment(*entry);
|
||||
}
|
||||
connection.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* NetworkTableClient.cpp
|
||||
*
|
||||
* Created on: Nov 3, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/client/NetworkTableClient.h"
|
||||
|
||||
/**
|
||||
* Create a new NetworkTable Client
|
||||
* @param streamFactory
|
||||
* @param threadManager
|
||||
* @param transactionPool
|
||||
*/
|
||||
NetworkTableClient::NetworkTableClient(IOStreamFactory& streamFactory, NetworkTableEntryTypeManager& typeManager, NTThreadManager& threadManager):
|
||||
NetworkTableNode(*new ClientNetworkTableEntryStore(*this)),
|
||||
adapter(*new ClientConnectionAdapter((ClientNetworkTableEntryStore&)entryStore, threadManager, streamFactory, *this, typeManager)),
|
||||
writeManager(*new WriteManager(adapter, threadManager, GetEntryStore(), 1000)),
|
||||
dirtier(new TransactionDirtier(writeManager)){
|
||||
|
||||
GetEntryStore().SetOutgoingReceiver(dirtier);
|
||||
GetEntryStore().SetIncomingReceiver(&OutgoingEntryReceiver_NULL);
|
||||
writeManager.start();
|
||||
}
|
||||
NetworkTableClient::~NetworkTableClient(){
|
||||
//Closing this now will cause a reconnect from the write manager -James
|
||||
//Close();
|
||||
delete &writeManager;
|
||||
delete &adapter;
|
||||
delete &entryStore;
|
||||
delete dirtier;
|
||||
}
|
||||
|
||||
/**
|
||||
* force the client to disconnect and reconnect to the server again. Will connect if the client is currently disconnected
|
||||
*/
|
||||
void NetworkTableClient::reconnect() {
|
||||
adapter.reconnect();
|
||||
}
|
||||
|
||||
void NetworkTableClient::Close() {
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
void NetworkTableClient::stop() {
|
||||
writeManager.stop();
|
||||
Close();
|
||||
}
|
||||
|
||||
bool NetworkTableClient::IsConnected() {
|
||||
return adapter.isConnected();
|
||||
}
|
||||
|
||||
bool NetworkTableClient::IsServer() {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* BadMessageException.cpp
|
||||
*
|
||||
* Created on: Sep 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/connection/BadMessageException.h"
|
||||
|
||||
BadMessageException::BadMessageException(const char* msg)
|
||||
: message(msg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BadMessageException::~BadMessageException() throw ()
|
||||
{
|
||||
}
|
||||
|
||||
const char* BadMessageException::what()
|
||||
{
|
||||
return message.c_str();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* ConnectionMonitorThread.cpp
|
||||
*
|
||||
* Created on: Sep 22, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/connection/ConnectionMonitorThread.h"
|
||||
#include "networktables2/connection/BadMessageException.h"
|
||||
#include "networktables2/util/System.h"
|
||||
|
||||
ConnectionMonitorThread::ConnectionMonitorThread(ConnectionAdapter& _adapter, NetworkTableConnection& _connection) :
|
||||
adapter(_adapter), connection(_connection) {
|
||||
}
|
||||
|
||||
void ConnectionMonitorThread::run() {
|
||||
|
||||
if (adapter.keepAlive())
|
||||
{
|
||||
try{
|
||||
connection.read(adapter);
|
||||
} catch(BadMessageException& e){
|
||||
adapter.badMessage(e);
|
||||
} catch(IOException& e){
|
||||
adapter.ioException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep_ms(10); //avoid busy-wait
|
||||
//Test to see this working properly
|
||||
//printf("--ConnectionMonitorThread::run Waiting to close\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "networktables2/connection/DataIOStream.h"
|
||||
|
||||
//TODO remove this when alloca is solved
|
||||
#ifdef WIN32
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
///This is used in case NULL is passed so all logic calls to IOstream can continue to assume there is never a null pointer
|
||||
class InertStream : public IOStream
|
||||
{
|
||||
protected:
|
||||
virtual int read(void* ptr, int numbytes) {return numbytes;} //return success
|
||||
virtual int write(const void* ptr, int numbytes) {return numbytes;}
|
||||
virtual void flush() {}
|
||||
virtual void close() {}
|
||||
};
|
||||
|
||||
static InertStream s_InertStream;
|
||||
|
||||
DataIOStream::DataIOStream(IOStream* _iostream) :
|
||||
iostream(_iostream)
|
||||
{
|
||||
}
|
||||
DataIOStream::~DataIOStream()
|
||||
{
|
||||
close();
|
||||
if (iostream!=&s_InertStream)
|
||||
delete iostream;
|
||||
}
|
||||
|
||||
void DataIOStream::SetIOStream(IOStream* stream)
|
||||
{
|
||||
IOStream *temp=iostream;
|
||||
iostream=stream ? stream : &s_InertStream; //We'll never assign NULL
|
||||
if (temp!=&s_InertStream)
|
||||
delete temp;
|
||||
}
|
||||
|
||||
void DataIOStream::close()
|
||||
{
|
||||
iostream->close();
|
||||
}
|
||||
|
||||
void DataIOStream::writeByte(uint8_t b)
|
||||
{
|
||||
iostream->write(&b, 1);
|
||||
}
|
||||
void DataIOStream::write2BytesBE(uint16_t s)
|
||||
{
|
||||
writeByte((uint8_t)(s >> 8));
|
||||
writeByte((uint8_t)s);
|
||||
}
|
||||
void DataIOStream::writeString(std::string& str)
|
||||
{
|
||||
write2BytesBE(str.length());
|
||||
iostream->write(str.c_str(), str.length());
|
||||
}
|
||||
void DataIOStream::flush()
|
||||
{
|
||||
iostream->flush();
|
||||
}
|
||||
uint8_t DataIOStream::readByte()
|
||||
{
|
||||
uint8_t value;
|
||||
iostream->read(&value, 1);
|
||||
return value;
|
||||
}
|
||||
uint16_t DataIOStream::read2BytesBE()
|
||||
{
|
||||
uint16_t value;
|
||||
value = readByte()<<8 | readByte();
|
||||
return value;
|
||||
}
|
||||
std::string* DataIOStream::readString()
|
||||
{
|
||||
|
||||
unsigned int byteLength = read2BytesBE();
|
||||
#ifndef WIN32
|
||||
uint8_t bytes[byteLength+1];//FIXME figure out why this doesn't work on windows
|
||||
#else
|
||||
uint8_t* bytes = (uint8_t*)alloca(byteLength+1);
|
||||
#endif
|
||||
iostream->read(bytes, byteLength);
|
||||
bytes[byteLength] = 0;
|
||||
return new std::string((char*)bytes);//FIXME implement UTF-8 aware version
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* An abstraction for the NetworkTable protocol
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
|
||||
#include "networktables2/connection/NetworkTableConnection.h"
|
||||
#include "networktables2/connection/BadMessageException.h"
|
||||
|
||||
|
||||
NetworkTableConnection::NetworkTableConnection(IOStream* _ioStream, NetworkTableEntryTypeManager& _typeManager) :
|
||||
ioStream(new DataIOStream(_ioStream)), typeManager(_typeManager) {
|
||||
isValid = true;
|
||||
}
|
||||
NetworkTableConnection::~NetworkTableConnection(){
|
||||
delete ioStream;
|
||||
}
|
||||
|
||||
void NetworkTableConnection::SetIOStream(IOStream* stream)
|
||||
{
|
||||
ioStream->SetIOStream(stream); //just passing through
|
||||
}
|
||||
|
||||
void NetworkTableConnection::close() {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
if (isValid) {
|
||||
isValid = false;
|
||||
ioStream->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void NetworkTableConnection::flush() {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
ioStream->flush();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableConnection::sendMessageHeader(
|
||||
NetworkTableMessageType messageType) {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
ioStream->writeByte((uint8_t) messageType);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableConnection::sendKeepAlive() {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
sendMessageHeader(KEEP_ALIVE);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableConnection::sendClientHello() {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
sendMessageHeader(CLIENT_HELLO);
|
||||
ioStream->write2BytesBE(PROTOCOL_REVISION);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
void NetworkTableConnection::sendServerHelloComplete() {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
sendMessageHeader(SERVER_HELLO_COMPLETE);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableConnection::sendProtocolVersionUnsupported() {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
sendMessageHeader(PROTOCOL_VERSION_UNSUPPORTED);
|
||||
ioStream->write2BytesBE(PROTOCOL_REVISION);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableConnection::sendEntryAssignment(NetworkTableEntry& entry) {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
sendMessageHeader(ENTRY_ASSIGNMENT);
|
||||
ioStream->writeString(entry.name);
|
||||
ioStream->writeByte(entry.GetType()->id);
|
||||
ioStream->write2BytesBE(entry.GetId());
|
||||
ioStream->write2BytesBE(entry.GetSequenceNumber());
|
||||
entry.SendValue(*ioStream);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableConnection::sendEntryUpdate(NetworkTableEntry& entry) {
|
||||
{
|
||||
NTSynchronized sync(WRITE_LOCK);
|
||||
sendMessageHeader(FIELD_UPDATE);
|
||||
ioStream->write2BytesBE(entry.GetId());
|
||||
ioStream->write2BytesBE(entry.GetSequenceNumber());
|
||||
entry.SendValue(*ioStream);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableConnection::read(ConnectionAdapter& adapter) {
|
||||
int messageType = ioStream->readByte();
|
||||
switch (messageType) {
|
||||
case KEEP_ALIVE:
|
||||
adapter.keepAlive();
|
||||
return;
|
||||
case CLIENT_HELLO: {
|
||||
uint16_t protocolRevision = ioStream->read2BytesBE();
|
||||
adapter.clientHello(protocolRevision);
|
||||
return;
|
||||
}
|
||||
case SERVER_HELLO_COMPLETE: {
|
||||
adapter.serverHelloComplete();
|
||||
return;
|
||||
}
|
||||
case PROTOCOL_VERSION_UNSUPPORTED: {
|
||||
uint16_t protocolRevision = ioStream->read2BytesBE();
|
||||
adapter.protocolVersionUnsupported(protocolRevision);
|
||||
return;
|
||||
}
|
||||
case ENTRY_ASSIGNMENT: {
|
||||
std::string* entryName = ioStream->readString();
|
||||
TypeId typeId = ioStream->readByte();
|
||||
NetworkTableEntryType* entryType = typeManager.GetType(typeId);
|
||||
if (!entryType){
|
||||
char exceptionMessageBuffer[50];
|
||||
sprintf (exceptionMessageBuffer, "Unknown data type: %#x", typeId);
|
||||
throw BadMessageException(exceptionMessageBuffer);
|
||||
}
|
||||
EntryId entryId = ioStream->read2BytesBE();
|
||||
SequenceNumber entrySequenceNumber = ioStream->read2BytesBE();
|
||||
EntryValue value = entryType->readValue(*ioStream);
|
||||
adapter.offerIncomingAssignment(new NetworkTableEntry(entryId, *entryName, entrySequenceNumber, entryType, value));
|
||||
entryType->deleteValue(value);
|
||||
delete entryName;
|
||||
return;
|
||||
}
|
||||
case FIELD_UPDATE: {
|
||||
EntryId entryId = ioStream->read2BytesBE();
|
||||
SequenceNumber entrySequenceNumber = ioStream->read2BytesBE();
|
||||
NetworkTableEntry* entry = adapter.GetEntry(entryId);
|
||||
if (!entry){
|
||||
char exceptionMessageBuffer[50];
|
||||
sprintf (exceptionMessageBuffer, "Received update for unknown entry id: %d", entryId);
|
||||
throw BadMessageException(exceptionMessageBuffer);
|
||||
}
|
||||
EntryValue value = entry->GetType()->readValue(*ioStream);
|
||||
|
||||
adapter.offerIncomingUpdate(entry, entrySequenceNumber, value);
|
||||
entry->GetType()->deleteValue(value);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
char exceptionMessageBuffer[50];
|
||||
sprintf (exceptionMessageBuffer, "Unknown Network Table Message Type: %d", messageType);
|
||||
throw BadMessageException(exceptionMessageBuffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* NetworkTableServer.cpp
|
||||
*
|
||||
* Created on: Sep 27, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/server/NetworkTableServer.h"
|
||||
#include "networktables2/server/ServerNetworkTableEntryStore.h"
|
||||
#include <iostream>
|
||||
#include <limits.h>
|
||||
|
||||
NetworkTableServer::NetworkTableServer(IOStreamProvider& _streamProvider, NetworkTableEntryTypeManager& typeManager, NTThreadManager& threadManager):
|
||||
NetworkTableNode(*new ServerNetworkTableEntryStore(*this)),
|
||||
streamProvider(_streamProvider),
|
||||
incomingStreamMonitor(streamProvider, (ServerNetworkTableEntryStore&)entryStore, *this, connectionList, typeManager, threadManager),
|
||||
connectionList(&incomingStreamMonitor),
|
||||
writeManager(connectionList, threadManager, GetEntryStore(), ULONG_MAX),
|
||||
continuingReceiver(writeManager){
|
||||
|
||||
GetEntryStore().SetIncomingReceiver(&continuingReceiver);
|
||||
GetEntryStore().SetOutgoingReceiver(&continuingReceiver);
|
||||
|
||||
incomingStreamMonitor.start();
|
||||
writeManager.start();
|
||||
}
|
||||
//TODO implement simplified NetworkTableServer constructor
|
||||
/*NetworkTableServer::NetworkTableServer(IOStreamProvider& streamProvider){
|
||||
this(streamProvider, new NetworkTableEntryTypeManager(), new DefaultThreadManager());
|
||||
}*/
|
||||
NetworkTableServer::~NetworkTableServer(){
|
||||
Close();
|
||||
delete &entryStore;
|
||||
}
|
||||
|
||||
void NetworkTableServer::Close(){
|
||||
try{
|
||||
incomingStreamMonitor.stop();
|
||||
writeManager.stop();
|
||||
connectionList.closeAll();
|
||||
} catch (const std::exception& ex) {
|
||||
//TODO print stack trace?
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTableServer::OnNewConnection(ServerConnectionAdapter& connectionAdapter) {
|
||||
connectionList.add(connectionAdapter);
|
||||
}
|
||||
|
||||
|
||||
bool NetworkTableServer::IsConnected() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NetworkTableServer::IsServer() {
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* ServerConnectionAdapter.cpp
|
||||
*
|
||||
* Created on: Sep 26, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/server/ServerConnectionAdapter.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
void ServerConnectionAdapter::gotoState(ServerConnectionState* newState){
|
||||
if(connectionState!=newState){
|
||||
fprintf(stdout, "[NT] %p entered connection state: %s\n", (void*)this, newState->toString());
|
||||
fflush(stdout);
|
||||
connectionState = newState;
|
||||
}
|
||||
}
|
||||
|
||||
ServerConnectionAdapter::ServerConnectionAdapter(IOStream* stream, ServerNetworkTableEntryStore& _entryStore, IncomingEntryReceiver& _transactionReceiver, ServerAdapterManager& _adapterListener, NetworkTableEntryTypeManager& typeManager, NTThreadManager& threadManager) :
|
||||
entryStore(_entryStore), transactionReceiver(_transactionReceiver), adapterListener(_adapterListener),
|
||||
connection(stream, typeManager), monitorThread(*this, connection), m_IsAdapterListenerClosed(false) {
|
||||
connectionState = &ServerConnectionState::CLIENT_DISCONNECTED;
|
||||
gotoState(&ServerConnectionState::GOT_CONNECTION_FROM_CLIENT);
|
||||
readThread = threadManager.newBlockingPeriodicThread(&monitorThread, "Server Connection Reader Thread");
|
||||
}
|
||||
|
||||
ServerConnectionAdapter::~ServerConnectionAdapter(){
|
||||
delete readThread;
|
||||
}
|
||||
|
||||
|
||||
void ServerConnectionAdapter::badMessage(BadMessageException& e) {
|
||||
fprintf(stdout, "[NT] Bad message: %s\n", e.what());
|
||||
fflush(stdout);
|
||||
gotoState(new ServerConnectionState_Error(e));
|
||||
adapterListener.close(*this, true);
|
||||
m_IsAdapterListenerClosed=true;
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::ioException(IOException& e) {
|
||||
fprintf(stdout, "[NT] IOException message: %s\n", e.what());
|
||||
fflush(stdout);
|
||||
if(e.isEOF())
|
||||
gotoState(&ServerConnectionState::CLIENT_DISCONNECTED);
|
||||
else
|
||||
gotoState(new ServerConnectionState_Error(e));
|
||||
adapterListener.close(*this, false);
|
||||
m_IsAdapterListenerClosed=true;
|
||||
}
|
||||
|
||||
|
||||
void ServerConnectionAdapter::shutdown(bool closeStream) {
|
||||
readThread->stop();
|
||||
if(closeStream)
|
||||
connection.close();
|
||||
}
|
||||
|
||||
bool ServerConnectionAdapter::keepAlive() {
|
||||
return !m_IsAdapterListenerClosed; //returns true as long as the adapter listener has not been flagged for closing
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::clientHello(ProtocolVersion protocolRevision) {
|
||||
if(connectionState!=&ServerConnectionState::GOT_CONNECTION_FROM_CLIENT)
|
||||
throw BadMessageException("A server should not receive a client hello after it has already connected/entered an error state");
|
||||
if(protocolRevision!=NetworkTableConnection::PROTOCOL_REVISION){
|
||||
connection.sendProtocolVersionUnsupported();
|
||||
throw BadMessageException("Client Connected with bad protocol revision");
|
||||
}
|
||||
else{
|
||||
entryStore.sendServerHello(connection);
|
||||
gotoState(&ServerConnectionState::CONNECTED_TO_CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::protocolVersionUnsupported(ProtocolVersion protocolRevision) {
|
||||
throw BadMessageException("A server should not receive a protocol version unsupported message");
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::serverHelloComplete() {
|
||||
throw BadMessageException("A server should not receive a server hello complete message");
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::offerIncomingAssignment(NetworkTableEntry* entry) {
|
||||
transactionReceiver.offerIncomingAssignment(entry);
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::offerIncomingUpdate(NetworkTableEntry* entry, SequenceNumber sequenceNumber, EntryValue value) {
|
||||
transactionReceiver.offerIncomingUpdate(entry, sequenceNumber, value);
|
||||
}
|
||||
|
||||
NetworkTableEntry* ServerConnectionAdapter::GetEntry(EntryId id) {
|
||||
return entryStore.GetEntry(id);
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::offerOutgoingAssignment(NetworkTableEntry* entry) {
|
||||
try {
|
||||
if(connectionState==&ServerConnectionState::CONNECTED_TO_CLIENT)
|
||||
connection.sendEntryAssignment(*entry);
|
||||
} catch (IOException& e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
void ServerConnectionAdapter::offerOutgoingUpdate(NetworkTableEntry* entry) {
|
||||
try {
|
||||
if(connectionState==&ServerConnectionState::CONNECTED_TO_CLIENT)
|
||||
connection.sendEntryUpdate(*entry);
|
||||
} catch (IOException& e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ServerConnectionAdapter::flush() {
|
||||
try {
|
||||
connection.flush();
|
||||
} catch (IOException& e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the state of the connection
|
||||
*/
|
||||
ServerConnectionState* ServerConnectionAdapter::getConnectionState() {
|
||||
return connectionState;
|
||||
}
|
||||
|
||||
void ServerConnectionAdapter::ensureAlive() {
|
||||
try {
|
||||
connection.sendKeepAlive();
|
||||
} catch (IOException& e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* ServerConnectionList.cpp
|
||||
*
|
||||
* Created on: Sep 26, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/server/ServerConnectionList.h"
|
||||
#include "networktables2/server/ServerIncomingStreamMonitor.h"
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
ServerConnectionList::ServerConnectionList(ServerIncomingStreamMonitor *Factory) : m_Factory(Factory)
|
||||
{
|
||||
}
|
||||
ServerConnectionList::~ServerConnectionList()
|
||||
{
|
||||
connectionsLock.take();
|
||||
closeAll();
|
||||
}
|
||||
|
||||
void ServerConnectionList::add(ServerConnectionAdapter& connection)
|
||||
{
|
||||
NTSynchronized sync(connectionsLock);
|
||||
connections.push_back(&connection);
|
||||
}
|
||||
|
||||
void ServerConnectionList::close(ServerConnectionAdapter& connectionAdapter, bool closeStream)
|
||||
{
|
||||
NTSynchronized sync(connectionsLock);
|
||||
std::vector<ServerConnectionAdapter*>::iterator connectionPosition = std::find(connections.begin(), connections.end(), &connectionAdapter);
|
||||
if (connectionPosition != connections.end() && (*connectionPosition)==&connectionAdapter)
|
||||
{
|
||||
fprintf(stdout, "[NT] Close: %p\n", (void*)&connectionAdapter);
|
||||
fflush(stdout);
|
||||
connections.erase(connectionPosition);
|
||||
m_Factory->close(&connectionAdapter);
|
||||
//connectionAdapter.shutdown(closeStream);
|
||||
//delete &connectionAdapter;
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnectionList::closeAll()
|
||||
{
|
||||
NTSynchronized sync(connectionsLock);
|
||||
while(connections.size() > 0)
|
||||
{
|
||||
close(*connections[0], true);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnectionList::offerOutgoingAssignment(NetworkTableEntry* entry)
|
||||
{
|
||||
NTSynchronized sync(connectionsLock);
|
||||
for(unsigned int i = 0; i < connections.size(); ++i)
|
||||
{
|
||||
connections[i]->offerOutgoingAssignment(entry);
|
||||
}
|
||||
}
|
||||
void ServerConnectionList::offerOutgoingUpdate(NetworkTableEntry* entry)
|
||||
{
|
||||
NTSynchronized sync(connectionsLock);
|
||||
for(unsigned int i = 0; i < connections.size(); ++i)
|
||||
{
|
||||
connections[i]->offerOutgoingUpdate(entry);
|
||||
}
|
||||
}
|
||||
void ServerConnectionList::flush()
|
||||
{
|
||||
NTSynchronized sync(connectionsLock);
|
||||
for(unsigned int i = 0; i < connections.size(); ++i)
|
||||
{
|
||||
connections[i]->flush();
|
||||
}
|
||||
}
|
||||
void ServerConnectionList::ensureAlive()
|
||||
{
|
||||
NTSynchronized sync(connectionsLock);
|
||||
for(unsigned int i = 0; i < connections.size(); ++i)
|
||||
{
|
||||
connections[i]->ensureAlive();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* ServerConnectionState.cpp
|
||||
*
|
||||
* Created on: Sep 27, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/server/ServerConnectionState.h"
|
||||
|
||||
ServerConnectionState ServerConnectionState::GOT_CONNECTION_FROM_CLIENT("GOT_CONNECTION_FROM_CLIENT");
|
||||
|
||||
ServerConnectionState ServerConnectionState::CONNECTED_TO_CLIENT("CONNECTED_TO_CLIENT");
|
||||
|
||||
ServerConnectionState ServerConnectionState::CLIENT_DISCONNECTED("CLIENT_DISCONNECTED");
|
||||
|
||||
|
||||
ServerConnectionState::ServerConnectionState(const char* _name):name(_name){
|
||||
}
|
||||
const char* ServerConnectionState::toString(){
|
||||
return name;
|
||||
}
|
||||
|
||||
ServerConnectionState_Error::ServerConnectionState_Error(std::exception& _e):ServerConnectionState("SERVER_ERROR"),e(_e){
|
||||
}
|
||||
const char* ServerConnectionState_Error::toString(){
|
||||
return "SERVER_ERROR";
|
||||
//TODO return "SERVER_ERROR: "+e.getClass()+": "+e.what();
|
||||
}
|
||||
std::exception& ServerConnectionState_Error::getException(){
|
||||
return e;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* ServerIncomingStreamMonitor.cpp
|
||||
*
|
||||
* Created on: Sep 26, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/server/ServerIncomingStreamMonitor.h"
|
||||
#include "networktables2/stream/IOStream.h"
|
||||
|
||||
ServerIncomingStreamMonitor::ServerIncomingStreamMonitor(IOStreamProvider& _streamProvider, ServerNetworkTableEntryStore& _entryStore,
|
||||
ServerIncomingConnectionListener& _incomingListener, ServerAdapterManager& _adapterListener, NetworkTableEntryTypeManager& _typeManager,
|
||||
NTThreadManager& _threadManager) :
|
||||
streamProvider(_streamProvider), entryStore(_entryStore), incomingListener(_incomingListener), adapterListener(_adapterListener),
|
||||
typeManager(_typeManager), threadManager(_threadManager), monitorThread(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
ServerIncomingStreamMonitor::~ServerIncomingStreamMonitor()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the monitor thread
|
||||
*/
|
||||
void ServerIncomingStreamMonitor::start()
|
||||
{
|
||||
if (monitorThread != NULL)
|
||||
stop();
|
||||
monitorThread = threadManager.newBlockingPeriodicThread(this, "Server Incoming Stream Monitor Thread");
|
||||
}
|
||||
/**
|
||||
* Stop the monitor thread
|
||||
*/
|
||||
void ServerIncomingStreamMonitor::stop()
|
||||
{
|
||||
if (monitorThread != NULL)
|
||||
{
|
||||
streamProvider.close(); //This would get called on deletion too
|
||||
NTThread *temp=monitorThread;
|
||||
monitorThread = NULL; //call this before stop for the check below to ensure a new server connection adapter will not happen
|
||||
temp->stop();
|
||||
delete temp;
|
||||
}
|
||||
}
|
||||
|
||||
void ServerIncomingStreamMonitor::run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (monitorThread!=NULL)
|
||||
{
|
||||
IOStream* newStream = streamProvider.accept();
|
||||
{
|
||||
NTSynchronized sync(BlockDeletionList);
|
||||
for (size_t i=0;i<m_DeletionList.size();i++)
|
||||
{
|
||||
ServerConnectionAdapter *Element=m_DeletionList[i];
|
||||
Element->shutdown(true); //TODO assume to always close stream
|
||||
delete Element;
|
||||
}
|
||||
m_DeletionList.clear();
|
||||
}
|
||||
//Note: monitorThread must be checked to avoid crash on exit
|
||||
// [8/31/2013 Terminator]
|
||||
if ((monitorThread!=NULL)&&(newStream != NULL))
|
||||
{
|
||||
ServerConnectionAdapter* connectionAdapter = new ServerConnectionAdapter(newStream, entryStore, entryStore, adapterListener, typeManager, threadManager);
|
||||
incomingListener.OnNewConnection(*connectionAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException& e)
|
||||
{
|
||||
//could not get a new stream for some reason. ignore and continue
|
||||
}
|
||||
}
|
||||
|
||||
void ServerIncomingStreamMonitor::close(ServerConnectionAdapter *Adapter)
|
||||
{
|
||||
NTSynchronized sync(BlockDeletionList);
|
||||
m_DeletionList.push_back(Adapter);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* ServerNetworkTableEntryStore.cpp
|
||||
*
|
||||
* Created on: Sep 26, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/server/ServerNetworkTableEntryStore.h"
|
||||
|
||||
ServerNetworkTableEntryStore::ServerNetworkTableEntryStore(TableListenerManager& _listenerManager) :
|
||||
AbstractNetworkTableEntryStore(_listenerManager)
|
||||
{
|
||||
nextId = (EntryId)0;
|
||||
}
|
||||
ServerNetworkTableEntryStore::~ServerNetworkTableEntryStore()
|
||||
{
|
||||
}
|
||||
|
||||
bool ServerNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry)
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
NetworkTableEntry* entry = namedEntries[newEntry->name];
|
||||
|
||||
if (entry == NULL)
|
||||
{
|
||||
newEntry->SetId(nextId++);
|
||||
idEntries[newEntry->GetId()] = newEntry;
|
||||
namedEntries[newEntry->name] = newEntry;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServerNetworkTableEntryStore::updateEntry(NetworkTableEntry* entry, SequenceNumber sequenceNumber, EntryValue value)
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
return entry->PutValue(sequenceNumber, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send all entries in the entry store as entry assignments in a single transaction
|
||||
* @param connection
|
||||
* @throws IOException
|
||||
*/
|
||||
void ServerNetworkTableEntryStore::sendServerHello(NetworkTableConnection& connection)
|
||||
{
|
||||
NTSynchronized sync(LOCK);
|
||||
std::map<std::string, NetworkTableEntry*>::iterator itr;
|
||||
for (itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
|
||||
{
|
||||
NetworkTableEntry* entry = itr->second;
|
||||
connection.sendEntryAssignment(*entry);
|
||||
}
|
||||
connection.sendServerHelloComplete();
|
||||
connection.flush();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* ArrayData.cpp
|
||||
*
|
||||
* Created on: Nov 14, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/ArrayData.h"
|
||||
#ifndef _WRS_KERNEL
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
|
||||
ArrayData::ArrayData(ArrayEntryType& type) : ComplexData(type), m_data_type(type){
|
||||
m_size = 0;
|
||||
data = NULL;
|
||||
}
|
||||
ArrayData::~ArrayData(){
|
||||
free(data);
|
||||
}
|
||||
|
||||
EntryValue ArrayData::_get(unsigned int index){//TODO bounds checking
|
||||
return data[index];
|
||||
}
|
||||
|
||||
void ArrayData::_set(unsigned int index, EntryValue value){//TODO bounds checking
|
||||
m_data_type.deleteElement(data[index]);
|
||||
data[index] = m_data_type.copyElement(value);
|
||||
}
|
||||
|
||||
void ArrayData::_add(EntryValue value){
|
||||
setSize(size()+1);
|
||||
data[size()-1] = m_data_type.copyElement(value);
|
||||
}
|
||||
|
||||
void ArrayData::remove(unsigned int index){
|
||||
//if(index<0 || index>=size())
|
||||
// throw IndexOutOfBoundsException();//TODO bounds check
|
||||
m_data_type.deleteElement(data[index]);
|
||||
EntryValue nullValue = {0};
|
||||
data[index] = nullValue;
|
||||
if(index < size()-1){
|
||||
memcpy(data+index, data+index+1, (size()-index-1) * sizeof(EntryValue));
|
||||
}
|
||||
setSize(size()-1);
|
||||
}
|
||||
void ArrayData::setSize(unsigned int newSize){
|
||||
if(newSize==m_size)//TODO bound check greater than max size
|
||||
return;
|
||||
EntryValue* newArray = (EntryValue*)malloc(newSize*sizeof(EntryValue));//TODO cache arrays
|
||||
if(newSize<m_size){
|
||||
memcpy(newArray, data, newSize * sizeof(EntryValue));
|
||||
for(unsigned int i = newSize; i<m_size; ++i)
|
||||
m_data_type.deleteElement(data[i]);
|
||||
}
|
||||
else{
|
||||
if(data!=NULL)
|
||||
memcpy(newArray, data, m_size * sizeof(EntryValue));
|
||||
else
|
||||
m_size = 0;//ensure that the current size is actually 0 otherwise will end up with uninitialized values in the array
|
||||
EntryValue nullValue = {0};
|
||||
for(unsigned int i = m_size; i<newSize; ++i)
|
||||
newArray[i] = nullValue;
|
||||
}
|
||||
if(data!=NULL)
|
||||
free(data);
|
||||
data = newArray;
|
||||
m_size = newSize;
|
||||
}
|
||||
unsigned int ArrayData::size(){
|
||||
return m_size;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* ArrayEntryType.cpp
|
||||
*
|
||||
* Created on: Nov 14, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/ArrayEntryType.h"
|
||||
|
||||
ArrayEntryType::ArrayEntryType(TypeId id, NetworkTableEntryType& elementType)
|
||||
: ComplexEntryType(id, "Array"), m_elementType(elementType){ //TODO super(id, "Array of [" + elementType.name + "]");
|
||||
}
|
||||
|
||||
EntryValue ArrayEntryType::copyElement(EntryValue value){
|
||||
return m_elementType.copyValue(value);
|
||||
}
|
||||
void ArrayEntryType::deleteElement(EntryValue value){
|
||||
m_elementType.deleteValue(value);
|
||||
}
|
||||
bool ArrayEntryType::areElementsEqual(EntryValue v1, EntryValue v2){
|
||||
return m_elementType.areEqual(v1, v2);
|
||||
}
|
||||
|
||||
|
||||
void ArrayEntryType::sendValue(EntryValue value, DataIOStream& os) {
|
||||
ArrayEntryData* dataArray = (ArrayEntryData*) value.ptr;
|
||||
/*if (dataArray->length > 255) {//TODO throw better exception
|
||||
throw IOException("Cannot write " + value + " as " + name + ". Arrays have a max length of 255 values");
|
||||
}*/
|
||||
os.writeByte(dataArray->length);
|
||||
for (int i = 0; i < dataArray->length; ++i) {
|
||||
m_elementType.sendValue(dataArray->array[i], os);
|
||||
}
|
||||
}
|
||||
|
||||
EntryValue ArrayEntryType::readValue(DataIOStream& is) {
|
||||
uint8_t length = is.readByte();
|
||||
EntryValue* array = (EntryValue*)malloc(length*sizeof(EntryValue));//TODO cache object arrays
|
||||
for (int i = 0; i < length; ++i) {
|
||||
array[i] = m_elementType.readValue(is);
|
||||
}
|
||||
|
||||
ArrayEntryData* dataArray = (ArrayEntryData*)malloc(sizeof(ArrayEntryData));
|
||||
dataArray->length = length;
|
||||
dataArray->array = array;
|
||||
|
||||
EntryValue eValue;
|
||||
eValue.ptr = dataArray;
|
||||
return eValue;
|
||||
}
|
||||
|
||||
EntryValue ArrayEntryType::copyValue(EntryValue value){
|
||||
ArrayEntryData* otherDataArray = (ArrayEntryData*) value.ptr;
|
||||
|
||||
EntryValue* array = (EntryValue*)malloc(otherDataArray->length*sizeof(EntryValue));
|
||||
for (int i = 0; i < otherDataArray->length; ++i) {
|
||||
array[i] = copyElement(otherDataArray->array[i]);
|
||||
}
|
||||
|
||||
ArrayEntryData* dataArray = (ArrayEntryData*)malloc(sizeof(ArrayEntryData));
|
||||
dataArray->length = otherDataArray->length;
|
||||
dataArray->array = array;
|
||||
|
||||
EntryValue eValue;
|
||||
eValue.ptr = dataArray;
|
||||
return eValue;
|
||||
}
|
||||
void ArrayEntryType::deleteValue(EntryValue value){
|
||||
ArrayEntryData* dataArray = (ArrayEntryData*) value.ptr;
|
||||
if(dataArray!=NULL){
|
||||
for (int i = 0; i < dataArray->length; ++i) {
|
||||
deleteElement(dataArray->array[i]);
|
||||
}
|
||||
if(dataArray->array != NULL)
|
||||
free(dataArray->array);
|
||||
|
||||
free(dataArray);
|
||||
}
|
||||
}
|
||||
bool ArrayEntryType::areEqual(EntryValue v1, EntryValue v2) {
|
||||
ArrayEntryData* a1 = (ArrayEntryData*) v1.ptr;
|
||||
ArrayEntryData* a2 = (ArrayEntryData*) v2.ptr;
|
||||
if(a1->length != a2->length)
|
||||
return false;
|
||||
for (int i = 0; i < a1->length; ++i) {
|
||||
if(!areElementsEqual(a1->array[i], a2->array[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
EntryValue ArrayEntryType::internalizeValue(std::string& key, ComplexData& externalRepresentation, EntryValue currentInteralValue) {
|
||||
// TODO: Argument 'key' appears unused.
|
||||
ArrayData& externalArrayData = (ArrayData&)externalRepresentation;
|
||||
|
||||
EntryValue eValue = currentInteralValue;
|
||||
ArrayEntryData* internalArray = (ArrayEntryData*) currentInteralValue.ptr;
|
||||
if(internalArray == NULL){
|
||||
internalArray = (ArrayEntryData*)malloc(sizeof(ArrayEntryData));
|
||||
internalArray->length = 0;
|
||||
internalArray->array = NULL;
|
||||
eValue.ptr = internalArray;
|
||||
}
|
||||
|
||||
if(internalArray->length==externalArrayData.size()){
|
||||
for(int i = 0; i<internalArray->length; ++i){
|
||||
deleteElement(internalArray->array[i]);
|
||||
internalArray->array[i] = copyElement(externalArrayData._get(i));
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(internalArray->array != NULL)
|
||||
free(internalArray->array);
|
||||
internalArray->length = externalArrayData.size();
|
||||
if(internalArray->length == 0)
|
||||
internalArray->array = NULL;
|
||||
else
|
||||
internalArray->array = (EntryValue*)malloc(externalArrayData.size()*sizeof(EntryValue));
|
||||
for (int i = 0; i < internalArray->length; ++i) {
|
||||
internalArray->array[i] = copyElement(externalArrayData._get(i));
|
||||
}
|
||||
}
|
||||
return eValue;
|
||||
}
|
||||
|
||||
void ArrayEntryType::exportValue(std::string& key, EntryValue internalData, ComplexData& externalRepresentation) {
|
||||
ArrayEntryData* internalArray = (ArrayEntryData*) internalData.ptr;
|
||||
ArrayData& externalArrayData = (ArrayData&)externalRepresentation;
|
||||
externalArrayData.setSize(internalArray->length);
|
||||
for(int i = 0; i<internalArray->length; ++i){
|
||||
externalArrayData._set(i, copyElement(internalArray->array[i]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* BooleanArray.cpp
|
||||
*
|
||||
* Created on: Nov 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/BooleanArray.h"
|
||||
#include "networktables2/type/DefaultEntryTypes.h"
|
||||
|
||||
|
||||
const TypeId BooleanArray::BOOLEAN_ARRAY_RAW_ID = 0x10;
|
||||
ArrayEntryType BooleanArray::TYPE(BOOLEAN_ARRAY_RAW_ID, DefaultEntryTypes::BOOLEAN);
|
||||
|
||||
BooleanArray::BooleanArray() : ArrayData(TYPE) {
|
||||
}
|
||||
|
||||
bool BooleanArray::get(int index){
|
||||
return _get(index).b;
|
||||
}
|
||||
|
||||
void BooleanArray::set(int index, bool value){
|
||||
EntryValue eValue;
|
||||
eValue.b = value;
|
||||
_set(index, eValue);
|
||||
}
|
||||
|
||||
void BooleanArray::add(bool value){
|
||||
EntryValue eValue;
|
||||
eValue.b = value;
|
||||
_add(eValue);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* ComplexData.cpp
|
||||
*
|
||||
* Created on: Sep 24, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/ComplexData.h"
|
||||
|
||||
|
||||
ComplexData::ComplexData(ComplexEntryType& _type) : type(_type){}
|
||||
|
||||
ComplexEntryType& ComplexData::GetType() {
|
||||
return type;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* ComplexEntryType.cpp
|
||||
*
|
||||
* Created on: Sep 24, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/ComplexEntryType.h"
|
||||
|
||||
|
||||
ComplexEntryType::ComplexEntryType(TypeId id, const char* name) : NetworkTableEntryType(id, name){}
|
||||
|
||||
bool ComplexEntryType::isComplex(){
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* DefaultEntryTypes.cpp
|
||||
*
|
||||
* Created on: Sep 24, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/DefaultEntryTypes.h"
|
||||
#include "networktables2/type/NetworkTableEntryType.h"
|
||||
#include "networktables2/connection/DataIOStream.h"
|
||||
#include "networktables2/type/BooleanArray.h"
|
||||
#include "networktables2/type/NumberArray.h"
|
||||
#include "networktables2/type/StringArray.h"
|
||||
|
||||
|
||||
DefaultEntryTypes::BOOLEAN_t DefaultEntryTypes::BOOLEAN;
|
||||
DefaultEntryTypes::DOUBLE_t DefaultEntryTypes::DOUBLE;
|
||||
DefaultEntryTypes::STRING_t DefaultEntryTypes::STRING;
|
||||
|
||||
DefaultEntryTypes::BOOLEAN_t::BOOLEAN_t() : NetworkTableEntryType(BOOLEAN_RAW_ID, "Boolean"){}
|
||||
void DefaultEntryTypes::BOOLEAN_t::sendValue(EntryValue value, DataIOStream& os) {
|
||||
os.writeByte(value.b);
|
||||
}
|
||||
EntryValue DefaultEntryTypes::BOOLEAN_t::readValue(DataIOStream& is) {
|
||||
EntryValue value;
|
||||
value.b = (is.readByte()!=0);
|
||||
return value;
|
||||
}
|
||||
bool DefaultEntryTypes::BOOLEAN_t::areEqual(EntryValue v1, EntryValue v2) {
|
||||
return v1.b == v2.b;
|
||||
}
|
||||
|
||||
DefaultEntryTypes::DOUBLE_t::DOUBLE_t() : NetworkTableEntryType(DOUBLE_RAW_ID, "Double"){}
|
||||
void DefaultEntryTypes::DOUBLE_t::sendValue(EntryValue eValue, DataIOStream& os) {
|
||||
uint64_t value = *reinterpret_cast<uint64_t*>(&eValue.f);
|
||||
for(int i = 0; i<8; ++i){
|
||||
os.writeByte((value>>56)&0xFF);
|
||||
value<<=8;
|
||||
}
|
||||
}
|
||||
EntryValue DefaultEntryTypes::DOUBLE_t::readValue(DataIOStream& is) {
|
||||
uint64_t value = 0;
|
||||
|
||||
for(int i = 0; i<8; ++i){
|
||||
value<<=8;
|
||||
value |= (is.readByte()&0xFF);
|
||||
}
|
||||
|
||||
EntryValue eValue;
|
||||
eValue.f = *reinterpret_cast<double*>(&value);
|
||||
return eValue;
|
||||
}
|
||||
bool DefaultEntryTypes::DOUBLE_t::areEqual(EntryValue v1, EntryValue v2) {
|
||||
return v1.f == v2.f;
|
||||
}
|
||||
|
||||
DefaultEntryTypes::STRING_t::STRING_t() : NetworkTableEntryType(STRING_RAW_ID, "String"){}
|
||||
void DefaultEntryTypes::STRING_t::sendValue(EntryValue value, DataIOStream& os) {
|
||||
os.writeString(*(std::string*)value.ptr);
|
||||
}
|
||||
EntryValue DefaultEntryTypes::STRING_t::readValue(DataIOStream& is) {
|
||||
EntryValue value;
|
||||
value.ptr = is.readString();
|
||||
return value;
|
||||
}
|
||||
EntryValue DefaultEntryTypes::STRING_t::copyValue(EntryValue value){
|
||||
if(value.ptr==NULL)
|
||||
return value;
|
||||
EntryValue newValue;
|
||||
newValue.ptr = new std::string(*((std::string*)value.ptr));
|
||||
return newValue;
|
||||
}
|
||||
void DefaultEntryTypes::STRING_t::deleteValue(EntryValue value){
|
||||
if(value.ptr!=NULL)
|
||||
delete (std::string*)value.ptr;
|
||||
}
|
||||
bool DefaultEntryTypes::STRING_t::areEqual(EntryValue v1, EntryValue v2) {
|
||||
std::string* str1 = (std::string*)v1.ptr;
|
||||
std::string* str2 = (std::string*)v2.ptr;
|
||||
return str1->compare(*str2)==0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DefaultEntryTypes::registerTypes(NetworkTableEntryTypeManager* manager){
|
||||
manager->RegisterType(BOOLEAN);
|
||||
manager->RegisterType(DOUBLE);
|
||||
manager->RegisterType(STRING);
|
||||
manager->RegisterType(BooleanArray::TYPE);
|
||||
manager->RegisterType(NumberArray::TYPE);
|
||||
manager->RegisterType(StringArray::TYPE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* NetworkTableEntryType.cpp
|
||||
*
|
||||
* Created on: Sep 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/NetworkTableEntryType.h"
|
||||
|
||||
|
||||
NetworkTableEntryType::NetworkTableEntryType(TypeId _id, const char* _name) : id(_id), name(_name){
|
||||
}
|
||||
NetworkTableEntryType::~NetworkTableEntryType(){
|
||||
}
|
||||
|
||||
EntryValue NetworkTableEntryType::copyValue(EntryValue value){
|
||||
return value;
|
||||
}
|
||||
void NetworkTableEntryType::deleteValue(EntryValue value){
|
||||
}
|
||||
|
||||
|
||||
bool NetworkTableEntryType::isComplex(){
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* NetworkTableEntryTypeManager.cpp
|
||||
*
|
||||
* Created on: Sep 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/NetworkTableEntryTypeManager.h"
|
||||
#include "networktables2/type/DefaultEntryTypes.h"
|
||||
|
||||
|
||||
NetworkTableEntryType* NetworkTableEntryTypeManager::GetType(TypeId id){
|
||||
return entryTypes[id];
|
||||
}
|
||||
|
||||
void NetworkTableEntryTypeManager::RegisterType(NetworkTableEntryType& type){
|
||||
entryTypes[type.id] = &type;
|
||||
}
|
||||
|
||||
NetworkTableEntryTypeManager::NetworkTableEntryTypeManager(){
|
||||
for(int i = 0; i<MAX_NUM_TABLE_ENTRY_TYPES; ++i)
|
||||
entryTypes[i] = NULL;
|
||||
|
||||
DefaultEntryTypes::registerTypes(this);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* NumberArray.cpp
|
||||
*
|
||||
* Created on: Nov 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/NumberArray.h"
|
||||
#include "networktables2/type/DefaultEntryTypes.h"
|
||||
|
||||
|
||||
const TypeId NumberArray::NUMBER_ARRAY_RAW_ID = 0x11;
|
||||
ArrayEntryType NumberArray::TYPE(NUMBER_ARRAY_RAW_ID, DefaultEntryTypes::DOUBLE);
|
||||
|
||||
NumberArray::NumberArray() : ArrayData(TYPE) {
|
||||
}
|
||||
|
||||
double NumberArray::get(int index){
|
||||
return _get(index).f;
|
||||
}
|
||||
|
||||
void NumberArray::set(int index, double value){
|
||||
EntryValue eValue;
|
||||
eValue.f = value;
|
||||
_set(index, eValue);
|
||||
}
|
||||
|
||||
void NumberArray::add(double value){
|
||||
EntryValue eValue;
|
||||
eValue.f = value;
|
||||
_add(eValue);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* StringArray
|
||||
*
|
||||
* Created on: Nov 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/type/StringArray.h"
|
||||
#include "networktables2/type/DefaultEntryTypes.h"
|
||||
|
||||
|
||||
const TypeId StringArray::STRING_ARRAY_RAW_ID = 0x12;
|
||||
ArrayEntryType StringArray::TYPE(STRING_ARRAY_RAW_ID, DefaultEntryTypes::STRING);
|
||||
|
||||
StringArray::StringArray() : ArrayData(TYPE) {
|
||||
}
|
||||
|
||||
std::string StringArray::get(int index){
|
||||
return *(std::string*)_get(index).ptr;
|
||||
}
|
||||
|
||||
void StringArray::set(int index, std::string value){
|
||||
EntryValue eValue;
|
||||
eValue.ptr = &value;
|
||||
_set(index, eValue);
|
||||
}
|
||||
|
||||
void StringArray::add(std::string value){
|
||||
EntryValue eValue;
|
||||
eValue.ptr = &value;
|
||||
_add(eValue);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* EOFException.cpp
|
||||
*
|
||||
* Created on: Oct 1, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
#include "networktables2/util/EOFException.h"
|
||||
|
||||
EOFException::EOFException() : IOException("End of File"){}
|
||||
EOFException::~EOFException() throw(){}
|
||||
|
||||
bool EOFException::isEOF(){
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* IOException.cpp
|
||||
*
|
||||
* Created on: Oct 1, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/util/IOException.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
IOException::IOException(const char* msg) : message(strdup(msg)), errorValue(0){}
|
||||
IOException::IOException(const char* msg, int _errorValue) : message(strdup(msg)), errorValue(_errorValue){}
|
||||
|
||||
const char* IOException::what(){
|
||||
return message;
|
||||
}
|
||||
|
||||
bool IOException::isEOF(){return false;}
|
||||
|
||||
IOException::~IOException() throw (){
|
||||
free((void*)message);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* IllegalStateException.cpp
|
||||
*
|
||||
* Created on: Sep 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "networktables2/util/IllegalStateException.h"
|
||||
|
||||
IllegalStateException::IllegalStateException(const char* msg)
|
||||
: message(msg)
|
||||
{
|
||||
}
|
||||
IllegalStateException::~IllegalStateException() throw ()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* StringCache.cpp
|
||||
*
|
||||
* Created on: Oct 16, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include "networktables2/util/StringCache.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
StringCache::StringCache(){
|
||||
}
|
||||
StringCache::~StringCache(){
|
||||
}
|
||||
|
||||
std::string& StringCache::Get(const std::string& input){
|
||||
map<std::string, std::string>::iterator itr = cache.find(input);
|
||||
if(itr != cache.end()){
|
||||
return itr->second;
|
||||
}
|
||||
else{
|
||||
cache[input] = Calc(input);
|
||||
return cache[input];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* TableKeyNotDefinedException.cpp
|
||||
*
|
||||
* Created on: Sep 22, 2012
|
||||
* Author: Mitchell Wills
|
||||
*/
|
||||
|
||||
#include "tables/TableKeyNotDefinedException.h"
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
#define MESSAGE_PREFIX "Unkown Table Key: "
|
||||
TableKeyNotDefinedException::TableKeyNotDefinedException(const std::string key):
|
||||
msg(MESSAGE_PREFIX + key){
|
||||
|
||||
}
|
||||
|
||||
const char* TableKeyNotDefinedException::what(){
|
||||
return msg.c_str();
|
||||
}
|
||||
|
||||
TableKeyNotDefinedException::~TableKeyNotDefinedException() throw(){
|
||||
}
|
||||
Reference in New Issue
Block a user