CMake Changes

This is the changes made by Patrick Plenefisch converting the native
code to use CMake and the CMake Maven Plugin, as opposed to the
native Maven plugin. This is to allow for compatibility with newer
versions of the GCC toolchain. All the cpp sources were moved from
maven style directories to cpp style directories for CMake.

Change-Id: I67f5e3608948f37c83b0990d232105a3784f8593
This commit is contained in:
Brad Miller
2014-03-24 16:13:08 -04:00
parent 33134bef1d
commit 69d9ad70ab
804 changed files with 586 additions and 9377 deletions

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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){}

View File

@@ -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
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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
}
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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");
}
}

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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]));
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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 ()
{
}

View File

@@ -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];
}
}