![]() |
User Manual, Developers Guide and API Documentation |
![]() |
00001 /******************************************************************************* 00002 * This file is part of openWNS (open Wireless Network Simulator) 00003 * _____________________________________________________________________________ 00004 * 00005 * Copyright (C) 2004-2007 00006 * Chair of Communication Networks (ComNets) 00007 * Kopernikusstr. 5, D-52074 Aachen, Germany 00008 * phone: ++49-241-80-27910, 00009 * fax: ++49-241-80-22242 00010 * email: info@openwns.org 00011 * www: http://www.openwns.org 00012 * _____________________________________________________________________________ 00013 * 00014 * openWNS is free software; you can redistribute it and/or modify it under the 00015 * terms of the GNU Lesser General Public License version 2 as published by the 00016 * Free Software Foundation; 00017 * 00018 * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY 00019 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 00020 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 00021 * details. 00022 * 00023 * You should have received a copy of the GNU Lesser General Public License 00024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00025 * 00026 ******************************************************************************/ 00027 00028 #include <WNS/ldk/CommandProxy.hpp> 00029 #include <WNS/ldk/CommandReaderInterface.hpp> 00030 #include <WNS/ldk/fun/FUN.hpp> 00031 #include <WNS/ldk/FunctionalUnit.hpp> 00032 #include <WNS/ldk/Command.hpp> 00033 #include <WNS/ldk/Compound.hpp> 00034 #include <WNS/TypeInfo.hpp> 00035 #include <WNS/Exception.hpp> 00036 #include <WNS/simulator/ISimulator.hpp> 00037 00038 using namespace wns::ldk; 00039 00040 CommandProxy::CommandIDType CommandProxy::serial = CommandIDType(0); 00041 00042 CommandProxy::CommandProxy(const wns::pyconfig::View& config) : 00043 logger(config.get("logger")) 00044 { 00045 wns::simulator::getResetSignal()->connect(&wns::ldk::CommandProxy::clearRegistries); 00046 } 00047 00048 00049 CommandProxy::~CommandProxy() 00050 { 00051 for (size_t ii = 0; ii < this->commandTypeSpecifiers.size(); ++ii) { 00052 if (this->commandTypeSpecifierCloned.at(ii)) { 00053 delete this->commandTypeSpecifiers.at(ii); 00054 } 00055 } 00056 00059 } // ~CommandProxy 00060 00061 00062 void 00063 CommandProxy::addFunctionalUnit( 00064 const std::string& commandName, 00065 CommandTypeSpecifierInterface* functionalUnit) 00066 { 00067 assure(functionalUnit != NULL, "Not a valid CommandTypeSpecifierInterface."); 00068 assure(functionalUnit->getFUN() != NULL, "CommandTypeSpecifierInterface is not attached to a fun::FUN."); 00069 assure(functionalUnit->getFUN()->getProxy() == this, "CommandProxy mismatch."); 00070 00071 // Registered FU at a global CommandIDRegistry 00072 if (this->getCommandIDRegistry().knows(commandName)) 00073 { 00074 CommandIDType id = this->getCommandIDRegistry().find(commandName); 00075 functionalUnit->setPCIID(id); 00076 if (id < this->commandTypeSpecifierCloned.size()) 00077 { 00078 if (this->commandTypeSpecifierCloned.at(id) == true) 00079 { 00080 // we are re-adding a formerly removed FU, so delete the clone 00081 delete this->commandTypeSpecifiers.at(id); 00082 this->commandTypeSpecifierCloned.at(id) = false; 00083 this->commandTypeSpecifiers.at(id) = functionalUnit; 00084 } 00085 } 00086 } 00087 else 00088 { 00089 this->getCommandIDRegistry().insert(commandName, serial); 00090 functionalUnit->setPCIID(serial); 00091 ++serial; 00092 } 00093 00094 // if container is too small: resize and set new elements to NULL 00095 if (this->commandTypeSpecifiers.size() <= functionalUnit->getPCIID()) { 00096 size_t oldSize = this->commandTypeSpecifiers.size(); 00097 this->commandTypeSpecifiers.resize(functionalUnit->getPCIID()+1); 00098 this->commandTypeSpecifierCloned.resize(functionalUnit->getPCIID()+1); 00099 for(size_t ii = oldSize; ii < this->commandTypeSpecifiers.size(); ++ii) { 00100 this->commandTypeSpecifiers.at(ii) = NULL; 00101 this->commandTypeSpecifierCloned.at(ii) = false; 00102 } 00103 } 00104 00105 if (this->commandTypeSpecifiers.at(functionalUnit->getPCIID()) == NULL) { 00106 this->commandTypeSpecifiers.at(functionalUnit->getPCIID()) = functionalUnit; 00107 MESSAGE_SINGLE(VERBOSE, logger, "Added FU to commandTypeSpecifiers List, Type is: " << wns::TypeInfo::create(*functionalUnit).toString()); 00108 } 00109 00110 // Keep a global list of CopyCommand Objects to enable 00111 // "partialCopy" 00112 if (! this->getCopyCommandRegistry().knows(functionalUnit->getPCIID())) 00113 { 00114 this->getCopyCommandRegistry().insert(functionalUnit->getPCIID(), 00115 functionalUnit->getCopyCommandInterface()); 00116 } 00117 else 00118 { 00119 // Make sure that the new CommandTypeSpecifier works on the same 00120 // command as the already known one. 00121 CopyCommandInterface* tmp = functionalUnit->getCopyCommandInterface(); 00122 assure ( wns::TypeInfo::create(*this->getCopyCommandRegistry().find(functionalUnit->getPCIID())) 00123 == 00124 wns::TypeInfo::create(*tmp), "forbidden commandName duplication ('"+commandName+"')" ); 00125 delete tmp; 00126 } 00127 00128 // Keep a global list of CommandReader Objects to access commands 00129 if (! this->getCommandReaderRegistry().knows(functionalUnit->getPCIID())) 00130 { 00131 this->getCommandReaderRegistry().insert(functionalUnit->getPCIID(), 00132 functionalUnit->getCommandReader(this)); 00133 } 00134 else 00135 { 00136 // Make sure that the new CommandTypeSpecifier works on the same 00137 // command as the already registered one. 00138 CommandReaderInterface* tmp = functionalUnit->getCommandReader(this); 00139 assure ( wns::TypeInfo::create(*this->getCommandReaderRegistry().find(functionalUnit->getPCIID())) 00140 == 00141 wns::TypeInfo::create(*tmp), "forbidden commandName duplication ('"+commandName+"')" ); 00142 delete tmp; 00143 } 00144 00145 } // addFunctionalUnit 00146 00147 00148 void 00149 CommandProxy::removeFunctionalUnit(const std::string& commandName) 00150 { 00151 if (!this->getCommandIDRegistry().knows(commandName)) 00152 { 00153 wns::Exception e; 00154 e << "Can't remove FU. FU commandName \"" << commandName << "\" unknown."; 00155 throw wns::Exception(e); 00156 } 00157 00158 CommandIDType id = this->getCommandIDRegistry().find(commandName); 00159 00160 if (this->commandTypeSpecifiers.at(id) == NULL) 00161 { 00162 wns::Exception e; 00163 e << "Can't remove FU. FU with commandName \"" << commandName 00164 << "\" does not exist in this FUN."; 00165 throw wns::Exception(e); 00166 } 00167 00168 if (this->commandTypeSpecifierCloned.at(id) == false) 00169 { 00170 CommandTypeSpecifierInterface* ctsi = this->commandTypeSpecifiers.at(id); 00171 assureType(ctsi, FunctionalUnit*); 00172 wns::CloneableInterface* clonedFU = dynamic_cast<FunctionalUnit*>(ctsi)->clone(); 00173 assureType(clonedFU, FunctionalUnit*); 00174 this->commandTypeSpecifiers.at(id) = dynamic_cast<FunctionalUnit*>(clonedFU); 00175 00176 this->commandTypeSpecifierCloned.at(id) = true; 00177 } 00178 } 00179 00180 00181 wns::ldk::Command* 00182 CommandProxy::getCommand( 00183 const CommandPool* commandPool, 00184 const CommandTypeSpecifierInterface* kind) const 00185 { 00186 assure(kind != NULL, "Invalid argument."); 00187 return this->getCommand(commandPool, kind->getPCIID()); 00188 } // getCommand 00189 00190 00191 wns::ldk::Command* 00192 CommandProxy::getCommand( 00193 const CommandPool* commandPool, 00194 CommandIDType n) const 00195 { 00196 assure(commandPool != NULL, "Invalid argument."); 00197 assure(commandPool->knows(n), 00198 "Command (Command ID: " << n << ") not activated in CommandPool. Only activated Commands may be retrieved." << 00199 "\nThe following commands are in the CommandPool:\n" << commandPool->dumpCommandTypes() << 00200 "\nThe following commands are registered at the CommandProxy:\n" << dumpCommandIDRegistry()); 00201 00202 Command* command = commandPool->find(n); 00203 00204 return command; 00205 } // getCommand 00206 00207 CommandReaderInterface* 00208 CommandProxy::getCommandReader(const std::string& role) const 00209 { 00210 assure(this->getCommandIDRegistry().knows(role), "ID for unknown role="<<role<<" requested. Available="<<dumpCommandIDRegistry()); 00211 unsigned long int id = this->getCommandIDRegistry().find(role); 00212 assure(this->getCommandReaderRegistry().knows(id), "CommandReader for unknown ID="<<id<<" requested."); 00213 return this->getCommandReaderRegistry().find(id); 00214 } // getCommandReader 00215 00216 bool 00217 CommandProxy::commandIsActivated( 00218 const CommandPool* commandPool, 00219 const CommandTypeSpecifierInterface* kind) const 00220 { 00221 assure(kind != NULL, "Invalid argument."); 00222 return this->commandIsActivated(commandPool, kind->getPCIID()); 00223 } // commandIsActivated 00224 00225 00226 bool 00227 CommandProxy::commandIsActivated( 00228 const CommandPool* commandPool, 00229 const CommandIDType& id) const 00230 { 00231 assure(commandPool != NULL, "Invalid argument."); 00232 return commandPool->knows(id); 00233 } 00234 00235 00236 wns::ldk::Command* 00237 CommandProxy::activateCommand( 00238 CommandPool* commandPool, 00239 const CommandTypeSpecifierInterface* kind) 00240 { 00241 assure(commandPool != NULL, "Invalid argument."); 00242 assure(kind != NULL, "Invalid argument."); 00243 assure(!commandPool->knows(kind->getPCIID()), 00244 "Command " << kind->getPCIID() 00245 << " already added to command pool. Trying to activate an already activated Command.\n" 00246 << dumpCommandIDRegistry()); 00247 00248 Command* command = kind->createCommand(); 00249 00250 commandPool->insert(kind->getPCIID(), command); 00251 00252 #ifndef NDEBUG 00253 for(CommandPool::PathContainer::const_iterator i = commandPool->path.begin(); 00254 i != commandPool->path.end(); 00255 ++i) 00256 assure(*i != kind->getPCIID(), "Corrupted path: trying to add a CommandTypeSpecifierInterface twice."); 00257 #endif 00258 commandPool->path.push_back(kind->getPCIID()); 00259 00260 return command; 00261 } // activateCommand 00262 00263 Command* 00264 CommandProxy::activateCommand( 00265 CommandPool* commandPool, 00266 const CommandIDType& id) 00267 { 00268 assure(commandPool != NULL, "Invalid argument."); 00269 assure(id < commandTypeSpecifiers.size(), "Invalid ID"); 00270 00271 return activateCommand(commandPool, commandTypeSpecifiers.at(id)); 00272 } 00273 00274 CommandPool* 00275 CommandProxy::createCommandPool(const fun::FUN* origin) const 00276 { 00277 return new CommandPool(this, origin); 00278 } // createCommandPool 00279 00280 00281 const CommandTypeSpecifierInterface* 00282 CommandProxy::getNext( 00283 const CommandPool* commandPool, 00284 const CommandTypeSpecifierInterface* questioner) const 00285 { 00286 if(!questioner) 00287 { 00288 if(commandPool->path.empty()) 00289 return NULL; 00290 00291 return getCommandTypeSpecifier(commandPool->path.back()); 00292 } 00293 00294 CommandPool::PathContainer::const_iterator i; 00295 for(i = commandPool->path.begin(); 00296 i != commandPool->path.end(); 00297 ++i) 00298 { 00299 if(*i == questioner->getPCIID()) 00300 break; 00301 } 00302 assure(i != commandPool->path.end(), "Questioner is not in path. This could mean that you have included a FU on the receiver side but not on the sender side."); 00303 00304 // delegate up one level. 00305 if(i == commandPool->path.begin()) 00306 return NULL; 00307 00308 --i; 00309 00310 return this->getCommandTypeSpecifier(*i); 00311 } // getNext 00312 00313 00314 CommandPool* 00315 CommandProxy::createReply( 00316 const CommandPool* original, 00317 const CommandTypeSpecifierInterface* questioner) const 00318 { 00319 const CommandTypeSpecifierInterface* next = this->getNext(original, questioner); 00320 00321 if(!next) 00322 return this->createCommandPool(); 00323 00324 return next->createReply(original); 00325 } // createReplyPCI 00326 00327 00328 void 00329 CommandProxy::calculateSizes( 00330 const CommandPool* commandPool, 00331 Bit& commandPoolSize, Bit& dataSize, 00332 const CommandTypeSpecifierInterface* questioner) const 00333 { 00334 const CommandTypeSpecifierInterface* next = this->getNext(commandPool, questioner); 00335 00336 if(next) 00337 { 00338 // Look at the next command in the chain, if its sizes are already commited we can stop 00339 // the recursion 00340 Command* nextCommand = commandPool->commands.at(next->getPCIID()); 00341 if ( nextCommand->sizeCommited() ) 00342 { 00343 // End recursion 00344 commandPoolSize = nextCommand->getCommandPoolSize(); 00345 dataSize = nextCommand->getPayloadSize(); 00346 MESSAGE_BEGIN(VERBOSE, logger,m,"End of recursion, already commited sizes "); 00347 m << " - commandPoolSize: " << commandPoolSize << " dataSize: " << dataSize; 00348 MESSAGE_END(); 00349 return; 00350 } 00351 else 00352 { 00353 // Continue recursion 00354 next->calculateSizes(commandPool, commandPoolSize, dataSize); 00355 MESSAGE_BEGIN(VERBOSE, logger,m,"Sizes after: "); 00356 m << dynamic_cast<const wns::ldk::FunctionalUnit*>(next)->getName() 00357 << " - commandPoolSize: " << commandPoolSize << " dataSize: " << dataSize; 00358 MESSAGE_END(); 00359 return; 00360 } 00361 } 00362 00363 // We have reached the beginning of the activation path, so we start 00364 // calculating with an empty commandPool and the original SDU size for 00365 // the data. 00366 commandPoolSize = 0; 00367 if(commandPool->getSDU()) 00368 dataSize = commandPool->getSDU()->getLengthInBits(); 00369 else 00370 dataSize = 0; 00371 00372 MESSAGE_BEGIN(VERBOSE, logger,m,"End of recursion, adding SDU size "); 00373 m << " - commandPoolSize: " << commandPoolSize << " dataSize: " << dataSize; 00374 MESSAGE_END(); 00375 } // calculateSizes 00376 00377 00378 void 00379 CommandProxy::commitSizes( 00380 CommandPool* commandPool, 00381 const CommandTypeSpecifierInterface* commiter) const 00382 { 00383 const CommandTypeSpecifierInterface* next = this->getNext(commandPool, commiter); 00384 00385 if(next) 00386 { 00387 Command* nextCommand = commandPool->commands.at(next->getPCIID()); 00388 00389 if ( nextCommand->sizeCommited() ) 00390 { 00391 // End of recursion, commit the commiters command Sizes 00392 Command* command = this->commit(commandPool, commiter); 00393 00394 MESSAGE_BEGIN(VERBOSE, logger,m,"End of recursion - beginning of non-commited Path ("); 00395 m << dynamic_cast<const wns::ldk::FunctionalUnit*>(next)->getName() << ")" 00396 << " - commandPoolSize: " << command->getCommandPoolSize() 00397 << " dataSize: " << command->getPayloadSize(); 00398 MESSAGE_END(); 00399 00400 return; 00401 00402 } 00403 else 00404 { 00405 // first continue recursion 00406 next->commitSizes(commandPool); 00407 // then commit my own command 00408 Command* command = this->commit(commandPool, commiter); 00409 00410 MESSAGE_BEGIN(VERBOSE, logger,m,"Sizes after: "); 00411 m << dynamic_cast<const wns::ldk::FunctionalUnit*>(commiter)->getName() 00412 << " - commandPoolSize: " << command->getCommandPoolSize() 00413 << " dataSize: " << command->getPayloadSize(); 00414 MESSAGE_END(); 00415 return; 00416 } 00417 } 00418 00419 // We have reached the beginning of the activation path, so we can 00420 // commit the commiter's command size 00421 Command* command = this->commit(commandPool, commiter); 00422 00423 MESSAGE_BEGIN(VERBOSE, logger,m,"End of recursion - beginning of activation Path ("); 00424 m << dynamic_cast<const wns::ldk::FunctionalUnit*>(commiter)->getName() << ")" 00425 << " - commandPoolSize: " << command->getCommandPoolSize() 00426 << " dataSize: " << command->getPayloadSize(); 00427 MESSAGE_END(); 00428 } // calculateSizes 00429 00430 void 00431 CommandProxy::commitSizes(CommandPool* commandPool, const CommandIDType& id) const 00432 { 00433 commitSizes(commandPool, getCommandTypeSpecifier(id)); 00434 } 00435 00436 wns::ldk::Command* 00437 CommandProxy::commit(CommandPool* commandPool, 00438 const CommandTypeSpecifierInterface* commiter) const 00439 { 00440 assure(commandPool != NULL, "No valid commandPool given."); 00441 assure(commiter != NULL, "No commiter set. " 00442 "Are you using the CommandProxy::commitSizes" 00443 "directly?. You should use the " 00444 "CommandTypeSpecifier::commitSizes."); 00445 00446 Command* command = commiter->getCommand(commandPool); 00447 Bit commandPoolSize = 0; 00448 Bit dataSize = 0; 00449 commiter->calculateSizes(commandPool, commandPoolSize, dataSize); 00450 command->setCommandPoolSize(commandPoolSize); 00451 command->setPayloadSize(dataSize); 00452 command->commit(); // makes the command Read-only 00453 return command; 00454 } 00455 00456 void 00457 CommandProxy::cleanup(CommandPool* commandPool) const 00458 { 00459 delete commandPool; 00460 } // cleanup 00461 00462 00463 void 00464 CommandProxy::copy(CommandPool* dst, const CommandPool* src) const 00465 { 00466 for(CommandPool::PathContainer::const_iterator it = src->path.begin(); 00467 it != src->path.end(); 00468 ++it) 00469 { 00470 CommandIDType id = *it; 00471 dst->insert(id, this->getCopyCommandRegistry().find(id)->copy(src->find(id))); 00472 dst->path.push_back(id); 00473 } 00474 } // copy 00475 00476 00477 void 00478 CommandProxy::partialCopy( 00479 const CommandTypeSpecifierInterface* initiator, 00480 CommandPool* dst, const CommandPool* src) const 00481 { 00482 CommandIDType initiatorID = initiator->getPCIID(); 00483 00484 CommandPool::PathContainer::const_iterator it = src->path.begin(); 00485 for(;it != src->path.end(); 00486 ++it) 00487 { 00488 CommandIDType id = *it; 00489 00490 if(id == initiatorID) 00491 break; 00492 00493 dst->insert(id, this->getCopyCommandRegistry().find(id)->copy(src->find(id))); 00494 dst->path.push_back(id); 00495 } 00496 assure(it != src->path.end(), "partial copy failed, initiator was not found in activation path"); 00497 } // partialCopy 00498 00499 00500 const CommandTypeSpecifierInterface* 00501 CommandProxy::getCommandTypeSpecifier(CommandIDType id) const 00502 { 00503 if (!this->commandTypeSpecifiers.at(id)) 00504 { 00505 //std::stringstream ss; 00506 //ss << id; 00507 //throw wns::Exception("Invalid CommandTypeSpecifier instance with id="+ss.str()+" requested."); 00508 // @todo: find a better way to cope with the lack of information here. 00509 MESSAGE_SINGLE(NORMAL, logger, "WARNING: Invalid CommandTypeSpecifier instance with id="<<(int)id<<" requested."); 00510 return NULL; 00511 } 00512 return this->commandTypeSpecifiers.at(id); 00513 } // getCommandTypeSpecifier 00514 00515 00516 CommandProxy::CommandIDRegistry& 00517 CommandProxy::getCommandIDRegistry() 00518 { 00519 static CommandIDRegistry registry; 00520 return registry; 00521 } 00522 00523 std::string 00524 CommandProxy::dumpCommandIDRegistry() 00525 { 00526 CommandIDRegistry& registry = getCommandIDRegistry(); 00527 std::stringstream str; 00528 for(CommandIDRegistry::const_iterator itr = registry.begin(); 00529 itr != registry.end(); 00530 ++itr) 00531 { 00532 str << "Command ID: " << itr->second << ", Role name: " << itr->first << "\n"; 00533 } 00534 return str.str(); 00535 } 00536 00537 CommandProxy::CopyCommandInterfaceRegistry& 00538 CommandProxy::getCopyCommandRegistry() 00539 { 00540 static CopyCommandInterfaceRegistry registry; 00541 return registry; 00542 } 00543 00544 CommandProxy::CommandReaderRegistry& 00545 CommandProxy::getCommandReaderRegistry() 00546 { 00547 static CommandReaderRegistry registry; 00548 return registry; 00549 } 00550 00551 void 00552 CommandProxy::clearRegistries() 00553 { 00554 CommandProxy::getCommandIDRegistry().clear(); 00555 CommandProxy::getCopyCommandRegistry().clear(); 00556 CommandProxy::getCommandReaderRegistry().clear(); 00557 } 00558 00559 #ifndef NDEBUG 00560 size_t 00561 CommandProxy::getCommandObjSize(const CommandIDType& id) const 00562 { 00563 const CommandTypeSpecifierInterface* commandTypeSpecifier 00564 = this->getCommandTypeSpecifier(id); 00565 if (commandTypeSpecifier != NULL) { 00566 return this->getCommandTypeSpecifier(id)->getCommandObjSize(); 00567 } else { 00568 return 0; 00569 } 00570 } 00571 #endif 00572 00573
1.5.5