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); } }
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(); } }
void NetworkTableConnection::sendEntryUpdate(NetworkTableEntry& entry) { { Synchronized sync(WRITE_LOCK); sendMessageHeader(FIELD_UPDATE); ioStream->write2BytesBE(entry.GetId()); ioStream->write2BytesBE(entry.GetSequenceNumber()); entry.SendValue(*ioStream); } }
/** * 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){ { Synchronized 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); } } }
void NetworkTableConnection::sendEntryAssignment(NetworkTableEntry& entry) { { Synchronized 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 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); } }
/** * Send all unknown entries in the entry store to the given connection * @param connection * @throws IOException */ void ClientNetworkTableEntryStore::sendUnknownEntries(NetworkTableConnection& connection) { { Synchronized sync(LOCK); std::map<std::string, NetworkTableEntry*>::iterator itr; for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++) { NetworkTableEntry* entry = (*itr).second; if(entry && entry->GetId()==NetworkTableEntry::UNKNOWN_ID) connection.sendEntryAssignment(*entry); } connection.flush(); } }
void WriteManager::run() { { Synchronized 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(); { Synchronized 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(); { Synchronized 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); }
/** * 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::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; } }
bool ClientNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry){ { Synchronized 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; }
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); }
std::string& NetworkTableNode::GetString(std::string& name) { NetworkTableEntry* entry = entryStore.GetEntry(name); if(entry==NULL) throw TableKeyNotDefinedException(name); return *(std::string*)(entry->GetValue().ptr); }
double NetworkTableNode::GetDouble(std::string& name){ NetworkTableEntry* entry = entryStore.GetEntry(name); if(entry==NULL) throw TableKeyNotDefinedException(name); return entry->GetValue().f; }