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 }