Now you can download a copy of these docs so you can use them offline! Download now
NetworkTable.cpp
00001 /*----------------------------------------------------------------------------*/ 00002 /* Copyright (c) FIRST 2011. All Rights Reserved. */ 00003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 00004 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ 00005 /*----------------------------------------------------------------------------*/ 00006 00007 #include "NetworkTables/NetworkTable.h" 00008 00009 #include "NetworkTables/BooleanEntry.h" 00010 #include "NetworkTables/Buffer.h" 00011 #include "NetworkTables/Connection.h" 00012 #include "NetworkTables/ConnectionManager.h" 00013 #include "NetworkTables/DoubleEntry.h" 00014 #include "NetworkTables/Entry.h" 00015 #include "NetworkTables/IntegerEntry.h" 00016 #include "NetworkTables/Key.h" 00017 #include "NetworkTables/NetworkQueue.h" 00018 #include "NetworkTables/NetworkTableChangeListener.h" 00019 #include "NetworkTables/NetworkTableAdditionListener.h" 00020 #include "NetworkTables/NetworkTableConnectionListener.h" 00021 #include "NetworkTables/StringEntry.h" 00022 #include "NetworkTables/TableEntry.h" 00023 #include "Synchronized.h" 00024 #include "WPIErrors.h" 00025 00026 NetworkTable::TableNameMap NetworkTable::_tableNameMap; 00027 NetworkTable::TableIdMap NetworkTable::_tableIdMap; 00028 UINT32 NetworkTable::_currentId = 1; 00029 bool NetworkTable::_initialized = false; 00030 SEM_ID NetworkTable::_staticMemberMutex = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE); 00031 00032 NetworkTable::NetworkTable() : 00033 m_dataLock(NULL), 00034 m_listenerLock(NULL), 00035 m_id(GrabId()), 00036 m_transaction(NULL), 00037 m_transactionCount(0), 00038 m_hasChanged(NULL), 00039 m_hasAdded(NULL) 00040 { 00041 m_dataLock = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE); 00042 m_listenerLock = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE); 00043 m_transaction = new NetworkTables::NetworkQueue(); 00044 m_hasChanged = new NetworkTables::NetworkQueue(); 00045 m_hasAdded = new NetworkTables::NetworkQueue(); 00046 } 00047 00048 NetworkTable::~NetworkTable() 00049 { 00050 delete m_hasAdded; 00051 delete m_hasChanged; 00052 delete m_transaction; 00053 semTake(m_listenerLock, WAIT_FOREVER); 00054 m_connectionListeners.clear(); 00055 m_additionListeners.clear(); 00056 m_listeners.clear(); 00057 m_listenToAllListeners.clear(); 00058 semDelete(m_listenerLock); 00059 semTake(m_dataLock, WAIT_FOREVER); 00060 m_connections.clear(); 00061 m_data.clear(); 00062 semDelete(m_dataLock); 00063 } 00064 00070 void NetworkTable::Initialize() 00071 { 00072 if (!_initialized) 00073 { 00074 _initialized = true; 00075 NetworkTables::ConnectionManager::GetInstance(); 00076 } 00077 } 00078 00085 NetworkTable *NetworkTable::GetTable(const char *tableName) 00086 { 00087 Initialize(); 00088 Synchronized sync(_staticMemberMutex); 00089 // Insert will add a new element if the key is not found 00090 // or will return the existing key if it is found. 00091 std::pair<TableNameMap::iterator, bool> ret = 00092 _tableNameMap.insert(TableNameMap::value_type(tableName, NULL)); 00093 if (ret.second) 00094 // Key not found. Create a table. 00095 ret.first->second = new NetworkTable(); 00096 return ret.first->second; 00097 } 00098 00099 NetworkTable *NetworkTable::GetTable(int id) 00100 { 00101 Synchronized sync(_staticMemberMutex); 00102 // Don't check if the id is in the map(assume it is) 00103 // If it's not, we will get the ID mapped to an uninitialized pointer (bad) 00104 // TODO: Validate success and error if not found 00105 return _tableIdMap[id]; 00106 } 00107 00108 std::vector<const char *> NetworkTable::GetKeys() 00109 { 00110 Synchronized sync(m_dataLock); 00111 std::vector<const char *> keys; 00112 keys.reserve(m_data.size()); 00113 DataMap::iterator it = m_data.begin(); 00114 DataMap::iterator end = m_data.end(); 00115 for (; it != end; it++) 00116 if (it->second->HasEntry()) 00117 keys.push_back(it->second->GetName().c_str()); 00118 return keys; 00119 } 00120 00124 void NetworkTable::BeginTransaction() 00125 { 00126 Synchronized sync(m_dataLock); 00127 m_transactionCount++; 00128 } 00129 00130 void NetworkTable::EndTransaction() 00131 { 00132 Synchronized sync(m_dataLock); 00133 if (m_transactionCount == 0) 00134 { 00135 wpi_setWPIErrorWithContext(NetworkTablesCorrupt, "EndTransaction() called too many times"); 00136 return; 00137 } 00138 else if (--m_transactionCount == 0) 00139 { 00140 ProcessTransaction(true, m_transaction); 00141 } 00142 } 00143 00150 void NetworkTable::AddChangeListener(const char *keyName, NetworkTableChangeListener *listener) 00151 { 00152 Synchronized sync(m_listenerLock); 00153 std::set<NetworkTableChangeListener *> emptyList; 00154 std::pair<ListenersMap::iterator, bool> listenersForKey = 00155 m_listeners.insert(ListenersMap::value_type(keyName, emptyList)); 00156 listenersForKey.first->second.insert(listener); 00157 } 00158 00164 void NetworkTable::AddChangeListenerAny(NetworkTableChangeListener *listener) 00165 { 00166 Synchronized sync(m_listenerLock); 00167 m_listenToAllListeners.insert(listener); 00168 } 00169 00176 void NetworkTable::RemoveChangeListener(const char *keyName, 00177 NetworkTableChangeListener *listener) 00178 { 00179 Synchronized sync(m_listenerLock); 00180 ListenersMap::iterator listenersForKey = m_listeners.find(keyName); 00181 if (listenersForKey != m_listeners.end()) 00182 listenersForKey->second.erase(listener); 00183 } 00184 00190 void NetworkTable::RemoveChangeListenerAny(NetworkTableChangeListener *listener) 00191 { 00192 Synchronized sync(m_listenerLock); 00193 m_listenToAllListeners.erase(listener); 00194 } 00195 00201 void NetworkTable::AddAdditionListener(NetworkTableAdditionListener *listener) 00202 { 00203 Synchronized sync(m_listenerLock); 00204 m_additionListeners.insert(listener); 00205 } 00206 00212 void NetworkTable::RemoveAdditionListener( 00213 NetworkTableAdditionListener *listener) 00214 { 00215 Synchronized sync(m_listenerLock); 00216 m_additionListeners.erase(listener); 00217 } 00218 00225 void NetworkTable::AddConnectionListener( 00226 NetworkTableConnectionListener *listener, bool immediateNotify) 00227 { 00228 Synchronized sync(m_listenerLock); 00229 m_connectionListeners.insert(listener); 00230 } 00231 00237 void NetworkTable::RemoveConnectionListener( 00238 NetworkTableConnectionListener *listener) 00239 { 00240 Synchronized sync(m_listenerLock); 00241 m_connectionListeners.erase(listener); 00242 } 00243 00249 bool NetworkTable::IsConnected() 00250 { 00251 Synchronized sync(m_dataLock); 00252 return m_connections.size() > 0; 00253 } 00254 00255 bool NetworkTable::ContainsKey(const char *keyName) 00256 { 00257 if (keyName == NULL) 00258 { 00259 wpi_setWPIErrorWithContext(NullParameter, "keyName"); 00260 return false; 00261 } 00262 Synchronized sync(m_dataLock); 00263 DataMap::iterator key = m_data.find(keyName); 00264 return key != m_data.end() && key->second->HasEntry(); 00265 } 00266 00272 NetworkTables::Entry *NetworkTable::GetEntry(const char *keyName) 00273 { 00274 if (keyName == NULL) 00275 { 00276 wpi_setWPIErrorWithContext(NullParameter, "keyName"); 00277 return NULL; 00278 } 00279 Synchronized sync(m_dataLock); 00280 DataMap::iterator key = m_data.find(keyName); 00281 if (key == m_data.end()) 00282 return NULL; 00283 return key->second->GetEntry(); 00284 } 00285 00291 int NetworkTable::GetInt(const char *keyName) 00292 { 00293 NetworkTables::Entry *entry = GetEntry(keyName); 00294 if (entry != NULL) 00295 { 00296 if (entry->GetType() == kNetworkTables_Types_INT) 00297 return entry->GetInt(); 00298 else 00299 wpi_setWPIError(NetworkTablesWrongType); 00300 } 00301 return 0; 00302 } 00303 00309 bool NetworkTable::GetBoolean(const char *keyName) 00310 { 00311 NetworkTables::Entry *entry = GetEntry(keyName); 00312 if (entry != NULL) 00313 { 00314 if (entry->GetType() == kNetworkTables_Types_BOOLEAN) 00315 return entry->GetBoolean(); 00316 else 00317 wpi_setWPIError(NetworkTablesWrongType); 00318 } 00319 return false; 00320 } 00321 00327 double NetworkTable::GetDouble(const char *keyName) 00328 { 00329 NetworkTables::Entry *entry = GetEntry(keyName); 00330 if (entry != NULL) 00331 { 00332 if (entry->GetType() == kNetworkTables_Types_DOUBLE) 00333 return entry->GetDouble(); 00334 else 00335 wpi_setWPIError(NetworkTablesWrongType); 00336 } 00337 return 0.0; 00338 } 00339 00345 int NetworkTable::GetString(const char *keyName, char *value, int len) 00346 { 00347 NetworkTables::Entry *entry = GetEntry(keyName); 00348 if (entry != NULL) 00349 { 00350 if (entry->GetType() == kNetworkTables_Types_STRING) 00351 return entry->GetString(value, len); 00352 else 00353 wpi_setWPIError(NetworkTablesWrongType); 00354 } 00355 return 0; 00356 } 00357 00358 std::string NetworkTable::GetString(std::string keyName) 00359 { 00360 NetworkTables::Entry *entry = GetEntry(keyName.c_str()); 00361 if (entry != NULL) 00362 { 00363 if (entry->GetType() == kNetworkTables_Types_STRING) 00364 return entry->GetString(); 00365 else 00366 wpi_setWPIError(NetworkTablesWrongType); 00367 } 00368 return ""; 00369 } 00370 00371 00377 NetworkTable *NetworkTable::GetSubTable(const char *keyName) 00378 { 00379 NetworkTables::Entry *entry = GetEntry(keyName); 00380 if (entry != NULL) 00381 { 00382 if (entry->GetType() == kNetworkTables_Types_TABLE) 00383 return entry->GetTable(); 00384 else 00385 wpi_setWPIError(NetworkTablesWrongType); 00386 } 00387 return NULL; 00388 } 00389 00397 void NetworkTable::PutInt(const char *keyName, int value) 00398 { 00399 Put(keyName, std::auto_ptr<NetworkTables::Entry>(new NetworkTables::IntegerEntry(value))); 00400 } 00401 00409 void NetworkTable::PutBoolean(const char *keyName, bool value) 00410 { 00411 Put(keyName, std::auto_ptr<NetworkTables::Entry>(new NetworkTables::BooleanEntry(value))); 00412 } 00413 00421 void NetworkTable::PutDouble(const char *keyName, double value) 00422 { 00423 Put(keyName, std::auto_ptr<NetworkTables::Entry>(new NetworkTables::DoubleEntry(value))); 00424 } 00425 00433 void NetworkTable::PutString(const char *keyName, const char *value) 00434 { 00435 if (value == NULL) 00436 { 00437 wpi_setWPIErrorWithContext(NullParameter, "value"); 00438 return; 00439 } 00440 Put(keyName, std::auto_ptr<NetworkTables::Entry>(new NetworkTables::StringEntry(value))); 00441 } 00442 00443 void NetworkTable::PutString(std::string keyName, std::string value) 00444 { 00445 PutString(keyName.c_str(), value.c_str()); 00446 } 00447 00455 void NetworkTable::PutSubTable(const char *keyName, NetworkTable *value) 00456 { 00457 if (value == NULL) 00458 { 00459 wpi_setWPIErrorWithContext(NullParameter, "value"); 00460 return; 00461 } 00462 Put(keyName, std::auto_ptr<NetworkTables::Entry>(new NetworkTables::TableEntry(value))); 00463 } 00464 00465 UINT32 NetworkTable::GrabId() 00466 { 00467 Synchronized sync(_staticMemberMutex); 00468 return _currentId++; 00469 } 00470 00471 void NetworkTable::ProcessTransaction(bool confirmed, NetworkTables::NetworkQueue *transaction) 00472 { 00473 if (transaction->IsEmpty()) 00474 return; 00475 00476 NetworkTables::Connection *source = ((NetworkTables::Entry *)transaction->Peek())->GetSource(); 00477 00478 Synchronized sync(m_dataLock); 00479 00480 std::set<NetworkTables::Connection *>::iterator it, end; 00481 it = m_connections.begin(); 00482 end = m_connections.end(); 00483 for (; it != end; it++) 00484 if (*it != source) 00485 (*it)->OfferTransaction(transaction); 00486 00487 while (!transaction->IsEmpty()) 00488 { 00489 std::pair<NetworkTables::Data *, bool> data = transaction->Poll(); 00490 // TODO: Remove this 00491 if (!data.second) 00492 printf("Internal error!"); 00493 std::auto_ptr<NetworkTables::Entry> entry = 00494 std::auto_ptr<NetworkTables::Entry>((NetworkTables::Entry *)data.first); 00495 std::auto_ptr<NetworkTables::Entry> oldEntry = entry->GetKey()->SetEntry(entry); 00496 if (oldEntry.get() == NULL) 00497 m_hasAdded->Offer(entry.get()); 00498 else // TODO: Filter unchanged values 00499 m_hasChanged->Offer(entry.get()); 00500 } 00501 while (!m_hasAdded->IsEmpty()) 00502 { 00503 NetworkTables::Entry *entry = (NetworkTables::Entry *)m_hasAdded->Poll().first; 00504 AlertListeners(true, confirmed, entry->GetKey()->GetName().c_str(), entry); 00505 } 00506 while (!m_hasChanged->IsEmpty()) 00507 { 00508 NetworkTables::Entry *entry = (NetworkTables::Entry *)m_hasChanged->Poll().first; 00509 AlertListeners(true, confirmed, entry->GetKey()->GetName().c_str(), entry); 00510 } 00511 } 00512 00513 void NetworkTable::AddConnection(NetworkTables::Connection *connection) 00514 { 00515 Synchronized sync(m_dataLock); 00516 00517 if (m_connections.insert(connection).second) 00518 { 00519 DataMap::iterator it = m_data.begin(); 00520 DataMap::iterator end = m_data.end(); 00521 for (; it != end; it++) 00522 { 00523 connection->Offer(it->second); 00524 if(it->second->HasEntry()) 00525 connection->Offer(it->second->GetEntry()); 00526 } 00527 if (m_connections.size() == 1) 00528 { 00529 Synchronized syncStatic(_staticMemberMutex); 00530 _tableIdMap.insert(TableIdMap::value_type(m_id, this)); 00531 00532 std::set<NetworkTableConnectionListener *>::iterator lit, lend; 00533 lit = m_connectionListeners.begin(); 00534 lend = m_connectionListeners.end(); 00535 for (; lit != lend; lit++) 00536 (*lit)->Connected(this); 00537 } 00538 } 00539 } 00540 00541 void NetworkTable::RemoveConnection(NetworkTables::Connection *connection) 00542 { 00543 Synchronized sync(m_dataLock); 00544 00545 m_connections.erase(connection); 00546 00547 if (m_connections.size() == 0) 00548 { 00549 Synchronized syncStatic(_staticMemberMutex); 00550 _tableIdMap.erase(m_id); 00551 00552 std::set<NetworkTableConnectionListener *>::iterator lit, lend; 00553 lit = m_connectionListeners.begin(); 00554 lend = m_connectionListeners.end(); 00555 for (; lit != lend; lit++) 00556 (*lit)->Disconnected(this); 00557 } 00558 } 00559 00566 NetworkTables::Key *NetworkTable::GetKey(const char *keyName) 00567 { 00568 Synchronized sync(m_dataLock); 00569 // Insert will add a new element if the key is not found 00570 // or will return the existing key if it is found. 00571 std::pair<DataMap::iterator, bool> ret = 00572 m_data.insert(DataMap::value_type(keyName, NULL)); 00573 if (ret.second) 00574 { 00575 // Key not found. Create a new one. 00576 ret.first->second = new NetworkTables::Key(this, keyName); 00577 if (m_connections.size() != 0) 00578 { 00579 std::set<NetworkTables::Connection *>::iterator it, end; 00580 it = m_connections.begin(); 00581 end = m_connections.end(); 00582 for (; it != end; it++) 00583 (*it)->Offer(ret.first->second); 00584 } 00585 } 00586 return ret.first->second; 00587 } 00588 00589 void NetworkTable::Put(const char *keyName, std::auto_ptr<NetworkTables::Entry> value) 00590 { 00591 if (keyName == NULL) 00592 { 00593 wpi_setWPIErrorWithContext(NullParameter, "keyName"); 00594 return; 00595 } 00596 Synchronized sync(m_dataLock); 00597 NetworkTables::Key *key = GetKey(keyName); 00598 value->SetKey(key); 00599 00600 if (m_transactionCount == 0) 00601 Got(true, key, value); 00602 else 00603 m_transaction->Offer(std::auto_ptr<NetworkTables::Data>(value.release())); 00604 } 00605 00606 void NetworkTable::Send(NetworkTables::Entry *entry) 00607 { 00608 Synchronized sync(m_dataLock); 00609 std::set<NetworkTables::Connection *>::iterator it, end; 00610 it = m_connections.begin(); 00611 end = m_connections.end(); 00612 for (; it != end; it++) 00613 if (*it != entry->GetSource()) 00614 (*it)->Offer(entry); 00615 } 00616 00624 void NetworkTable::Got(bool confirmed, NetworkTables::Key *key, std::auto_ptr<NetworkTables::Entry> value) 00625 { 00626 std::auto_ptr<NetworkTables::Entry> old; 00627 { 00628 Synchronized sync(m_dataLock); 00629 old = key->SetEntry(value); 00630 } 00631 // TODO: return if value didn't change 00632 00633 Send(key->GetEntry()); 00634 AlertListeners(old.get() == NULL, confirmed, key->GetName().c_str(), key->GetEntry()); 00635 } 00636 00637 void NetworkTable::AlertListeners(bool isNew, bool confirmed, const char *keyName, 00638 NetworkTables::Entry *value) 00639 { 00640 Synchronized sync(m_listenerLock); 00641 00642 if (isNew && m_additionListeners.size() != 0) 00643 { 00644 std::set<NetworkTableAdditionListener *>::iterator lit, lend; 00645 lit = m_additionListeners.begin(); 00646 lend = m_additionListeners.end(); 00647 for (; lit != lend; lit++) 00648 (*lit)->FieldAdded(this, keyName, value->GetType()); 00649 } 00650 00651 ListenersMap::iterator listeners = m_listeners.find(keyName); 00652 if (listeners != m_listeners.end()) 00653 { 00654 std::set<NetworkTableChangeListener *>::iterator lit, lend; 00655 lit = listeners->second.begin(); 00656 lend = listeners->second.end(); 00657 for (; lit != lend; lit++) 00658 { 00659 if (confirmed) 00660 (*lit)->ValueConfirmed(this, keyName, value->GetType()); 00661 else 00662 (*lit)->ValueChanged(this, keyName, value->GetType()); 00663 } 00664 } 00665 00666 { 00667 std::set<NetworkTableChangeListener *>::iterator lit, lend; 00668 lit = m_listenToAllListeners.begin(); 00669 lend = m_listenToAllListeners.end(); 00670 for (; lit != lend; lit++) 00671 { 00672 if (confirmed) 00673 (*lit)->ValueConfirmed(this, keyName, value->GetType()); 00674 else 00675 (*lit)->ValueChanged(this, keyName, value->GetType()); 00676 } 00677 } 00678 } 00679 00680 void NetworkTable::EncodeName(NetworkTables::Buffer *buffer) 00681 { 00682 buffer->WriteTableId(m_id); 00683 }
Generated on Thu Jan 12 2012 22:35:21 for WPILibC++ by
1.7.1