CCA
|
Component.cpp
Go to the documentation of this file.
00001 /* ============================================================ 00002 * 00003 * This file is a part of CCA project 00004 * 00005 * Copyright (C) 2011 by Arne Nordmann <anordman at cor-lab dot uni-bielefeld dot de> 00006 * 00007 * This file may be licensed under the terms of the 00008 * GNU Lesser General Public License Version 3 (the ``LGPL''), 00009 * or (at your option) any later version. 00010 * 00011 * Software distributed under the License is distributed 00012 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either 00013 * express or implied. See the LGPL for the specific language 00014 * governing rights and limitations. 00015 * 00016 * You should have received a copy of the LGPL along with this 00017 * program. If not, go to http://www.gnu.org/licenses/lgpl.html 00018 * or write to the Free Software Foundation, Inc., 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00020 * 00021 * The development of this software was supported by: 00022 * CoR-Lab, Research Institute for Cognition and Robotics 00023 * Bielefeld University 00024 * 00025 * ============================================================ */ 00026 00027 #include "Component.h" 00028 00029 #include <boost/format.hpp> 00030 #include <boost/algorithm/string.hpp> 00031 00032 #include <rsb/converter/Repository.h> 00033 00034 #include "cca/config.h" 00035 #include "cca/processing/Strategies.h" 00036 #include "cca/component/State.h" 00037 #include "cca/component/Info.h" 00038 #include "cca/component/converters/StateConverter.h" 00039 00040 #include "cca/timing/converters/TickConverter.h" 00041 #include "cca/processing/Timed.h" 00042 00043 using namespace std; 00044 using namespace boost; 00045 using namespace boost::algorithm; 00046 using namespace rsb; 00047 using namespace rsb::converter; 00048 using namespace rsc; 00049 using namespace rsc::logging; 00050 00051 namespace cca { 00052 00053 using namespace cca::timing; 00054 using namespace cca::timing::converters; 00055 00056 Component::Component(const string &compname, ComponentStatePtr initState) : 00057 Node(compname), state(initState), inputBeat(), inputState(), 00058 outputState(), lastTick(), circuitTime(), circuitVirtualTime(), 00059 circuitLastTimestep(), circuitLastVirtualTimestep(), 00060 circuitSequence(), scopename(), 00061 logger(Logger::getLogger("cca.component")), 00062 initialState(initState) { 00063 RSCINFO(logger, this->getName() + " Component created"); 00064 00065 // Try registering converter for component states 00066 try { 00067 boost::shared_ptr<ComponentStateConverter> converter( 00068 new ComponentStateConverter()); 00069 converterRepository<std::string>()->registerConverter(converter); 00070 } catch (const std::invalid_argument& e) { 00071 logger->info(e.what()); 00072 } 00073 00074 // Try registering converter for ticks 00075 try { 00076 boost::shared_ptr<TickConverter> converter(new TickConverter()); 00077 converterRepository<std::string>()->registerConverter(converter); 00078 } catch (const std::invalid_argument& e) { 00079 logger->info(e.what()); 00080 } 00081 00082 // A component always has a state change port and a beat port 00083 this->createBeatInputPort(); 00084 this->createStateInputPort(); 00085 this->createStateOutputPort(); 00086 } 00087 00088 Component::~Component() { 00089 if (this->state->getState() == ComponentState::STATE_EXEC) { 00090 this->onStopExecution(); 00091 } else if (this->state->getState() == ComponentState::STATE_ONLLEARN) { 00092 this->onStopLearnOnline(); 00093 } else { 00094 this->onStopLearnOffline(); 00095 } 00096 this->stop(); 00097 this->state = ComponentState::STOPPED(); 00098 this->publishState(); 00099 } 00100 00101 void Component::onProcess() { 00102 RSCTRACE(logger, this->getName() + " onProcess() Hook is empty"); 00103 /* User-defined prcoessing goes here */ 00104 } 00105 00106 void Component::onLearnOffline() { 00107 RSCTRACE(logger, this->getName() + " onLearnOffline() Hook is empty"); 00108 /* User-defined learning goes here */ 00109 } 00110 00111 void Component::onLearnOnlineBeforeProcess() { 00112 RSCTRACE(logger, 00113 this->getName() + " onLearnOnlineBeforeProcess() Hook is empty"); 00114 /* User defined online-learning goes here */ 00115 } 00116 00117 void Component::onLearnOnlineAfterProcess() { 00118 RSCTRACE(logger, 00119 this->getName() + " onLearnOnlineAfterProcess() Hook is empty"); 00120 /* User defined online-learning goes here */ 00121 } 00122 00123 bool Component::requestTransition(const ComponentStatePtr& st) { 00124 bool success = false; 00125 RSCTRACE(logger, 00126 this->getName() + " requestTransition() Transition into state " 00127 + st->print() + " requested"); 00128 00129 if (st->getState() == this->state->getState()) { 00130 RSCDEBUG(logger, 00131 this->getName() 00132 + " requestTransition() Component already in state " 00133 + st->print() + ", doing nothing."); 00134 success = this->resume(); 00135 return success; 00136 } else { 00137 RSCTRACE(logger, 00138 this->getName() + " requestTransition() Leaving current state " 00139 + this->state->print()); 00140 if ((this->state->getState() == ComponentState::STATE_EXEC) 00141 || (this->state->getState() == ComponentState::STATE_ONLLEARN) 00142 || (this->state->getState() == ComponentState::STATE_OFFLLEARN)) { 00143 if (this->state->getState() == ComponentState::STATE_EXEC) { 00144 RSCTRACE(logger, 00145 this->getName() 00146 + " requestTransition() Calling onStopExecution hook"); 00147 this->onStopExecution(); 00148 } else if (this->state->getState() 00149 == ComponentState::STATE_ONLLEARN) { 00150 RSCTRACE(logger, 00151 this->getName() 00152 + " requestTransition() Calling onStopLearnOnline hook"); 00153 this->onStopLearnOnline(); 00154 } else { 00155 RSCTRACE(logger, 00156 this->getName() 00157 + " requestTransition() Calling onStopLearnOffline hook"); 00158 this->onStopLearnOffline(); 00159 } 00160 } 00161 } 00162 00163 // Bring the component fully up 00164 if ((st->getState() == ComponentState::STATE_EXEC) 00165 || (st->getState() == ComponentState::STATE_ONLLEARN) 00166 || (st->getState() == ComponentState::STATE_OFFLLEARN)) { 00167 success = this->resume(); 00168 if (st->getState() == ComponentState::STATE_EXEC) { 00169 this->onStartExecution(); 00170 } else if (st->getState() == ComponentState::STATE_ONLLEARN) { 00171 this->onStartLearnOnline(); 00172 } else { 00173 this->onStartLearnOffline(); 00174 } 00175 } 00176 00177 // Reset 00178 if (st->getState() == ComponentState::STATE_RESET) { 00179 success = this->reset(); 00180 } 00181 00182 // Pause/Stop 00183 if ((st->getState() == ComponentState::STATE_PAUSE) 00184 || (st->getState() == ComponentState::STATE_OFF)) { 00185 if (this->state->getState() == ComponentState::STATE_EXEC) { 00186 this->onStopExecution(); 00187 } else if (this->state->getState() == ComponentState::STATE_ONLLEARN) { 00188 this->onStopLearnOnline(); 00189 } else if (this->state->getState() == ComponentState::STATE_OFFLLEARN) { 00190 this->onStopLearnOffline(); 00191 } 00192 success = this->stop(); 00193 } 00194 00195 // Load 00196 if (st->getState() == ComponentState::STATE_LOAD) { 00197 success = this->load(); 00198 } 00199 00200 // Persist 00201 if (st->getState() == ComponentState::STATE_PERSIST) { 00202 success = this->persist(); 00203 } 00204 00205 // Persist 00206 if (st->getState() == ComponentState::STATE_OFF) { 00207 success = this->stop(); 00208 } 00209 00210 // Requested state change was successful 00211 if (success) { 00212 this->state = st; 00213 RSCINFO(logger, 00214 this->getName() 00215 + " requestTransition() Successful transition into state " 00216 + this->state->print()); 00217 this->publishState(); 00218 return true; 00219 } 00220 00221 return false; 00222 } 00223 00224 void Component::beatCallback(EventPtr event) { 00225 RSCTRACE(logger, 00226 str( 00227 format( 00228 "%s::beatCallback() Component received tick from remote beat over scope %s") 00229 % this->getName() 00230 % event->getScopePtr()->toString())); 00231 00232 lastTick = inputBeat->get(); 00233 RSCINFO(logger, 00234 str( 00235 format( 00236 "%s::beatCallback() Tick with sequence number: %d and timestamp: %d") 00237 % this->getName() % lastTick->getSequenceNumber() 00238 % lastTick->getTimeStamp())); 00239 00240 circuitSequence = lastTick->getSequenceNumber(); 00241 circuitTime = lastTick->getTimeStamp(); 00242 circuitVirtualTime = lastTick->getVirtualTimeStamp(); 00243 circuitLastTimestep = lastTick->getTimeStep(); 00244 circuitLastVirtualTimestep = lastTick->getVirtualTimeStep(); 00245 00246 if (!isConfigured()) { 00247 RSCERROR(logger, 00248 this->getName() + " beatCallback() " 00249 + "Can`t work yet, component is not fully configured."); 00250 } 00251 00252 this->tick(); 00253 } 00254 00255 void Component::stateCallback(EventPtr event) { 00256 RSCTRACE(logger, 00257 this->getName() 00258 + " stateCallback() Component received state change request"); 00259 if (!isConfigured()) { 00260 RSCERROR(logger, 00261 this->getName() + " stateCallback() " 00262 + "Can`t work yet, component is not fully configured."); 00263 } 00264 00265 this->requestTransition( 00266 boost::static_pointer_cast<ComponentState>(event->getData())); 00267 } 00268 00269 void Component::process() { 00270 RSCTRACE(logger, this->getName() + " process()"); 00271 00272 if (!this->isConfigured()) { 00273 return; 00274 } 00275 00276 if (this->state->getState() == ComponentState::STATE_EXEC) { 00277 RSCTRACE(logger, 00278 this->getName() + " process() Execution state, calling " 00279 + "process of parent class"); 00280 Node::process(); 00281 return; 00282 } 00283 00284 if (this->state->getState() == ComponentState::STATE_ONLLEARN) { 00285 RSCTRACE(logger, 00286 this->getName() + " process() Online learning state, " 00287 + "calling user hook onLearnOnlineBeforeProcess()"); 00288 try { 00289 this->onLearnOnlineBeforeProcess(); 00290 } catch (...) { 00291 std::cout << std::endl 00292 << "ERROR in onLearnOnlineBeforeProcess() of '" 00293 << this->getName() << "':" << std::endl << this->print() 00294 << std::endl 00295 << "onLearnOnlineBeforeProcess() triggered by strategy '" 00296 << this->getProcessingStrategy()->print() 00297 << "'. Backtrace was:" << std::endl << std::endl; 00298 throw; 00299 } 00300 RSCTRACE(logger, 00301 this->getName() + " process() Online learning state, " 00302 + "calling process of parent class"); 00303 Node::process(); 00304 RSCTRACE(logger, 00305 this->getName() + " process() Online learning state, " 00306 + "calling user hook onLearnOnlineBeforeProcess()"); 00307 try { 00308 this->onLearnOnlineAfterProcess(); 00309 } catch (...) { 00310 std::cout << std::endl 00311 << "ERROR in onLearnOnlineAfterProcess() of '" 00312 << this->getName() << "':" << std::endl << this->print() 00313 << std::endl 00314 << "onLearnOnlineAfterProcess() triggered by strategy '" 00315 << this->getProcessingStrategy()->print() 00316 << "'. Backtrace was:" << std::endl << std::endl; 00317 throw; 00318 } 00319 return; 00320 } 00321 00322 if (this->state->getState() == ComponentState::STATE_OFFLLEARN) { 00323 RSCTRACE(logger, 00324 this->getName() + " process() Offline learning state, " 00325 + "calling user hook onLearnOffline()"); 00326 try { 00327 this->onLearnOffline(); 00328 } catch (...) { 00329 std::cout << std::endl << "ERROR in onLearnOffline() of '" 00330 << this->getName() << "':" << std::endl << this->print() 00331 << std::endl << "onLearnOffline() triggered by strategy '" 00332 << this->getProcessingStrategy()->print() 00333 << "'. Backtrace was:" << std::endl << std::endl; 00334 throw; 00335 } 00336 return; 00337 } 00338 00339 RSCDEBUG(logger, 00340 this->getName() + "::process() Component is paused or stopped."); 00341 } 00342 00343 void Component::publishState() { 00344 RSCTRACE(logger, 00345 getName() + "::publishState() Publishing own component state"); 00346 00347 if (outputState->isReady()) { 00348 outputState->publish( 00349 boost::shared_ptr<ComponentState>( 00350 new ComponentState(*this->state))); 00351 } else { 00352 RSCWARN(logger, 00353 getName() + "::publishState() Can't publish, port not ready"); 00354 } 00355 } 00356 00357 std::string Component::print() const { 00358 ComponentInfoPtr ci(new ComponentInfo(getName())); 00359 ci->displayStrategy(getProcessingStrategy()); 00360 ci->displayDataPorts(inputPorts, outputPorts); 00361 ci->displayBeatPort(inputBeat); 00362 ci->displayStatePorts(inputState, outputState); 00363 ci->displayProperties(defaultProperties, properties); 00364 ci->displayComponentState(this->state); 00365 return ci->print(); 00366 } 00367 00368 void Component::createBeatInputPort() { 00369 RSCTRACE(logger, this->getName() + " createBeatInputPort()"); 00370 00371 // Set-up port 00372 this->inputBeat = InputPort<cca::timing::Tick>::create(); 00373 this->inputBeat->setHandler( 00374 HandlerPtr( 00375 new EventFunctionHandler( 00376 bind(&Component::beatCallback, this, _1)))); 00377 00378 // Default port configuration 00379 try { 00380 this->configureBeatInputPort( 00381 PortConfiguration::LOCALREMOTE(CCA_DEFAULTSCOPE_HEARTBEAT)); 00382 } catch (...) { 00383 try { 00384 this->configureBeatInputPort( 00385 PortConfiguration::REMOTE(CCA_DEFAULTSCOPE_HEARTBEAT)); 00386 } catch (...) { 00387 try { 00388 this->configureBeatInputPort( 00389 PortConfiguration::LOCAL(CCA_DEFAULTSCOPE_HEARTBEAT)); 00390 } catch (...) { 00391 RSCERROR(logger, 00392 getName() + "::createBeatInputPort() Can't apply " 00393 + "default configuration, component won't receive " 00394 + "a remote beat unless configured properly."); 00395 return; 00396 } 00397 RSCWARN(logger, 00398 getName() + "::createBeatInputPort() Can't apply " 00399 + "any remote transport, component will only receive " 00400 + "local beats unless configured properly."); 00401 } 00402 } 00403 00404 } 00405 00406 void Component::configureBeatInputPort(PortConfigurationPtr portcfg) { 00407 RSCTRACE(logger, this->getName() + " configureBeatInputPort()"); 00408 00409 this->inputBeat->configure(portcfg); 00410 } 00411 00412 void Component::createStateInputPort() { 00413 RSCTRACE(logger, this->getName() + " createStateInputPort()"); 00414 00415 // Set-up port 00416 this->inputState = InputPort<ComponentState>::create(); 00417 this->inputState->setHandler( 00418 HandlerPtr( 00419 new EventFunctionHandler( 00420 bind(&Component::stateCallback, this, _1)))); 00421 00422 std::string scopename = "/cca/comp/" + this->scopeName() + "/statechange"; 00423 00424 // Default port configuration 00425 try { 00426 this->configureStateInputPort( 00427 PortConfiguration::LOCALREMOTE(scopename)); 00428 } catch (...) { 00429 try { 00430 this->configureStateInputPort(PortConfiguration::REMOTE(scopename)); 00431 } catch (...) { 00432 try { 00433 this->configureStateInputPort( 00434 PortConfiguration::LOCAL(scopename)); 00435 } catch (...) { 00436 RSCERROR(logger, 00437 getName() + "::createStateInputPort() Can't apply " 00438 + "default configuration, component state won't be remote controlled " 00439 + "unless configured properly."); 00440 return; 00441 } 00442 RSCWARN(logger, 00443 getName() + "::createStateInputPort() Can't apply " 00444 + "remote transport, component state will only be controllable " 00445 + "locally unless configured properly."); 00446 } 00447 } 00448 } 00449 00450 void Component::configureStateInputPort(PortConfigurationPtr portcfg) { 00451 RSCTRACE(logger, this->getName() + " configureStateInputPort()"); 00452 this->inputState->configure(portcfg); 00453 } 00454 00455 void Component::createStateOutputPort() { 00456 RSCTRACE(logger, this->getName() + " createStateOutputPort()"); 00457 00458 // Set-up port 00459 this->outputState = OutputPort<ComponentState>::create(); 00460 00461 std::string scopename = "/cca/comp/states/" + this->scopeName(); 00462 00463 // Default port configuration 00464 try { 00465 this->configureStateOutputPort( 00466 PortConfiguration::LOCALREMOTE(scopename)); 00467 } catch (...) { 00468 try { 00469 this->configureStateOutputPort( 00470 PortConfiguration::REMOTE(scopename)); 00471 } catch (...) { 00472 try { 00473 this->configureStateOutputPort( 00474 PortConfiguration::LOCAL(scopename)); 00475 } catch (...) { 00476 RSCERROR(logger, 00477 getName() + "::createStateOutputPort() Can't apply " 00478 + "default configuration, component won't publish it's " 00479 + "state unless configured properly."); 00480 return; 00481 } 00482 RSCWARN(logger, 00483 getName() + "::createStateOutputPort() Can't apply " 00484 + "remote transport, component will publish it's " 00485 + "state only locally unless configured properly."); 00486 } 00487 } 00488 } 00489 00490 void Component::configureStateOutputPort(PortConfigurationPtr portcfg) { 00491 RSCTRACE(logger, this->getName() + " configureStateOutputPort()"); 00492 this->outputState->configure(portcfg); 00493 } 00494 00495 std::string Component::scopeName() { 00496 if (scopename.empty()) { 00497 scopename = this->getName(); 00498 replace_all(scopename, "-", ""); 00499 replace_all(scopename, "_", ""); 00500 replace_all(scopename, " ", ""); 00501 replace_all(scopename, ".", ""); 00502 replace_all(scopename, "/", ""); 00503 replace_all(scopename, "+", ""); 00504 replace_all(scopename, "*", ""); 00505 } 00506 return scopename; 00507 } 00508 00509 void Component::onStartExecution() { 00510 } 00511 00512 void Component::onStopExecution() { 00513 } 00514 00515 void Component::onStartLearnOffline() { 00516 } 00517 00518 void Component::onStopLearnOffline() { 00519 } 00520 00521 void Component::onStartLearnOnline() { 00522 } 00523 00524 void Component::onStopLearnOnline() { 00525 } 00526 00527 }