iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tests/test-Module.C
/*! @file
@author Laurent Itti
@copyright GNU Public License (GPL v3)
@section License
@verbatim
// ////////////////////////////////////////////////////////////////////////
// The iLab Neuromorphic Robotics Toolkit (NRT) //
// Copyright 2010-2012 by the University of Southern California (USC) //
// and the iLab at USC. //
// //
// iLab - University of Southern California //
// Hedco Neurociences Building, Room HNB-10 //
// Los Angeles, Ca 90089-2520 - USA //
// //
// See http://ilab.usc.edu for information about this project. //
// ////////////////////////////////////////////////////////////////////////
// This file is part of The iLab Neuromorphic Robotics Toolkit. //
// //
// The iLab Neuromorphic Robotics Toolkit is free software: you can //
// redistribute it and/or modify it under the terms of the GNU General //
// Public License as published by the Free Software Foundation, either //
// version 3 of the License, or (at your option) any later version. //
// //
// The iLab Neuromorphic Robotics Toolkit is distributed in the hope //
// that it will be useful, but WITHOUT ANY WARRANTY; without even the //
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
// PURPOSE. See the GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with The iLab Neuromorphic Robotics Toolkit. If not, see //
// <http://www.gnu.org/licenses/>. //
// ////////////////////////////////////////////////////////////////////////
@endverbatim */
#include <nrt/Core/Typing/Macros.H> // for NRT_MACRO_WHERE
#include <iostream>
class MessageA : public nrt::MessageBase {
public:
template<class Archive> inline void serialize(Archive& ar) { }
};
class MessageB : public nrt::MessageBase {
public:
template<class Archive> inline void serialize(Archive& ar) { }
};
class MessageC : public nrt::MessageBase {
public:
template<class Archive> inline void serialize(Archive& ar) { }
};
class MessageD : public nrt::MessageBase {
public:
template<class Archive> inline void serialize(Archive& ar) { }
};
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputA, MessageA, void, "MessageA Output");
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputB, MessageB, void, "MessageB Output");
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputCraw, MessageC, MessageA, "MessageC Output, raw data");
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputCfilt, MessageC, MessageA, "MessageC Output, filtered data");
NRT_DECLARE_MESSAGEPOSTER_PORT(PostTestMM, MessageA, MessageB, "PostTest<MessageA, MessageB>");
NRT_DECLARE_MESSAGEPOSTER_PORT(PostTestMV, MessageA, void, "PostTest<MessageA, void>");
NRT_DECLARE_MESSAGECHECKER_PORT(AsyncInputA, MessageA, "MessageA Async Input");
NRT_DECLARE_MESSAGECHECKER_PORT(AsyncInputC, MessageC, "MessageC Async Input");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputA, MessageA, void, "MessageA Input");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputCleft, MessageC, MessageA, "MessageC Input, Left side");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputCright, MessageC, MessageA, "MessageC Input, Right side");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(SubscriTestMM, MessageA, MessageB, "SubscriTest<MessageA, MessageB>");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(SubscriTestMV, MessageA, void, "SubscriTest<MessageA, void>");
NRT_DECLARE_PARAMETER(dims, nrt::Dims<int>, "Dimensions to use", nrt::Dims<int>());
// ######################################################################
//! What you derive from determines what you will be allowed to do when interacting with the Blackboard
class MyModule : public nrt::Module,
public nrt::MessagePoster<OutputA, OutputB, OutputCraw, OutputCfilt, PostTestMM, PostTestMV>,
public nrt::MessageChecker<AsyncInputA, AsyncInputC>,
public nrt::MessageSubscriber<InputA, InputCleft, InputCright, SubscriTestMM, SubscriTestMV>,
public nrt::Parameter<dims>
{
public:
// ######################################################################
//! Example constructor with instanceID
MyModule(std::string const & instanceid = "") : nrt::Module(instanceid) { }
// ######################################################################
//! Example post()
void tryPost()
{
NRT_INFO("START: Testing post() functionality");
// can use: post(MessageA):
std::unique_ptr<MessageA> m(new MessageA);
NRT_INFO("Posting MessageA...");
OutputA::post(m); // this blocks until all callbacks are complete
NRT_INFO("Done posting MessageA.");
// can use: post(MessageB):
std::unique_ptr<MessageB> m2(new MessageB);
NRT_INFO("Posting MessageB...");
if (auto r = OutputB::post(m2)) r.waitgetall();
NRT_INFO("Done posting MessageB.");
// can use: post(MessageC): simpler syntax
auto m3 = OutputCraw::make_message(); // make_message could take args and forward them to message constructor
NRT_INFO("Posting MessageC...");
OutputCraw::PostResultsType res = OutputCraw::post(m3);
NRT_INFO("Done posting MessageC.");
// once posted, a message is gone (the unique_ptr has been reset to nullptr):
if (m3) NRT_FATAL("Posted Message not stolen!");
// cannot use post(MessageD) since we don't derive from MessagePoster<MessageD>:
std::unique_ptr<MessageD> m4(new MessageD);
//OutputD::post(m4); // error: no matching function
// wait until our post of MessageC has completed all callbacks. Beware that res may be null if there were no
// matching callbacks:
if (res) res.waitgetall();
NRT_INFO("Done with results of MessageC post.");
// more tests...
std::unique_ptr<MessageA> ptmm(new MessageA);
PostTestMM::post(ptmm);
std::unique_ptr<MessageA> ptmv(new MessageA);
PostTestMV::post(ptmv);
NRT_INFO("DONE: Testing post() functionality");
}
// ######################################################################
//! Example check()
{
NRT_INFO("START: Testing check() functionality");
// can use: AsyncInputA::check()
if (nrt::MessageCheckerResults<MessageA> res = AsyncInputA::check(mcp)) {
// use the results...
while(res.exhausted() == false)
try
{
auto msg = res.get();
if (msg) NRT_INFO("Got a result from check()!");
}
NRT_WARNING(" Received Blackboard exception from check() -- PROPAGATING IT");
throw;
// Note that if you are not going to handle the exception, no need to catch it here, can just skip this
// entire catch statement, the Blackboard will build a recursive stack trace automatically...
NRT_WARNING(" Received Module exception from check() -- PROPAGATING IT");
throw;
// Note that if you are not going to handle the exception, no need to catch it here, can just skip this
// entire catch statement, the Blackboard will build a recursive stack trace automatically...
} catch (...) {
NRT_WARNING(" Received unknown exception from check()! Re-throwing it.");
throw; // or we could just throw a ModuleException instead if we want perfect forwarding over the network
}
}
else NRT_DEBUG("No MessageA on the Blackboard");
NRT_INFO("DONE: Testing check() functionality");
}
// ######################################################################
void tryExpunge()
{
NRT_INFO("START: Testing expunge() functionality");
PostTestMV::expunge();
NRT_INFO("DONE: Testing expunge() functionality");
}
// ######################################################################
//! Message callback for MessageA
virtual void onMessage(InputA::InPtr msg)
{ NRT_DEBUG("serving MessageA"); }
// ######################################################################
//! Message callback for MessageC (first callback)
virtual std::unique_ptr<MessageA> onMessage(InputCleft::InPtr msg)
{
NRT_DEBUG("serving MessageC, left side");
return std::unique_ptr<MessageA>(new MessageA);
}
// ######################################################################
//! Message callback for MessageC (second callback)
// example of simpled syntax
virtual InputCright::OutPtr onMessage(InputCright::InPtr msg)
{
NRT_DEBUG("serving MessageC, right side");
return InputCright::make_return_message(); // make_return_message could forward args to message constructor
}
// ######################################################################
//! Message callback for SubscriTestMM
virtual std::unique_ptr<MessageB> onMessage(SubscriTestMM::InPtr msg)
{
NRT_DEBUG("serving SubscriTestMM");
return std::unique_ptr<MessageB>(new MessageB);
}
// ######################################################################
//! Message callback for SubscriTestMV
virtual void onMessage(SubscriTestMV::InPtr msg)
{
NRT_DEBUG("serving SubscriTestMV");
}
};
// ######################################################################
// ######################################################################
// ######################################################################
// Test of namespaces, connectors
class MessageZ : public nrt::MessageBase {
public:
template<class Archive> inline void serialize(Archive& ar) { }
};
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputZ, MessageZ, void, "MessageZ Output");
NRT_DECLARE_MESSAGECHECKER_PORT(AsyncInputZ, MessageZ, "MessageZ Async Input");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputZ, MessageZ, void, "MessageZ Input");
class TestModule : public nrt::Module,
public nrt::MessagePoster<OutputZ>,
public nrt::MessageChecker<AsyncInputZ>,
public nrt::MessageSubscriber<InputZ>
{
public:
TestModule(std::string const & instanceid = "") : nrt::Module(instanceid) { }
virtual ~TestModule() { }
virtual void onMessage(InputZ::InPtr msg) { NRT_DEBUG("serving MessageZ"); }
};
// ######################################################################
// ######################################################################
// ######################################################################
//! Test main function demonstrating use of Blackboard
int main(int argc, char const* argv[])
{
try
{
// Get a handle onto our Blackboard:
// Set some default args, in particular, we are master by default:
bb.setParamVal("master", true);
// Get command-line args:
bb.setCommandLineArgs(argc, argv);
// Parse command line and get operational (configure network, etc):
bb.init();
// Create some modules:
auto m = bb.addModule<MyModule>("My Module");
// mess with namespace, topic, etc
m->setNamespace("CoolSpace");
m->InputA::setTopicFilter(".*");
m->AsyncInputA::setTopicFilter(".*");
m->SubscriTestMM::setTopicFilter(".*"); // need to investigate this
// Build some complicated mess with a bunch of TestModule objects:
auto t1 = bb.addModule<TestModule>("t1");
auto t2 = bb.addModule<TestModule>("t2");
auto t3 = bb.addModule<TestModule>("t3");
// t1 is in the root namespace
t1->OutputZ::setTopic("base topic of t1");
t1->InputZ::setTopicFilter("tap");
// t2 is in a deep namespace
t2->setNamespace("ns1/ns2/ns3");
// add a connector from ns1/ns2/ns3 to ns1/ns2
t2->OutputZ::make_connector("t2pc1", "ns1/ns2/ns3", nrt::ConnectorType::Border, ".*", "top");
// add a connector from ns1/ns2 to ns1
t2->OutputZ::make_connector("t2pc2", "ns1/ns2", nrt::ConnectorType::Border, "top*", "tip");
// add a connector from ns1 to root
t2->OutputZ::make_connector("t2pc3", "ns1", nrt::ConnectorType::Border, "tip+", "tap");
// t3 in ns1/nsX
t3->setNamespace("ns1/nsX");
t3->OutputZ::setTopic("base topic of t3");
t3->InputZ::setTopicFilter(".*");
t3->AsyncInputZ::setTopicFilter(".*");
// add a checker connector from ns1/nsX to ns1
t3->AsyncInputZ::make_connector("t3cc", "ns1/nsX", nrt::ConnectorType::Border, "tip", ".*");
// add a subscriber connector from ns1/nsX to ns1
t3->InputZ::make_connector("t3sc", "ns1/nsX", nrt::ConnectorType::Border, "x", ".*");
// add a subscriber connector from ns1/ns2 to ns1
t3->InputZ::make_connector("t3sc2", "ns1/ns2", nrt::ConnectorType::Border, "top", "x+");
// soooo...
// t2::OutputZ should now be connected to t1::InputZ
// t3::AsyncInputZ should be connected to t2::OutputZ
// t3::InputZ should be connected to t2::OutputZ, actual connection is in ns1/ns2
/* DISBALED FOR NOW...
// try to create some ports for our param:
m->createParamPort(nrt::ModuleParamPort::Poster, "dims");
m->createParamPort(nrt::ModuleParamPort::Checker, "dims");
m->createParamPort(nrt::ModuleParamPort::Subscriber, "dims");
m->createParamPort(nrt::ModuleParamPort::Subscriber, "dims"); // no problem
*/
// get started:
bb.fedlaunch();
bb.printInfo(std::cout);
// post a Message:
m->tryPost();
// make sure all callbacks are completed to avoid clashing in printing messages
usleep(300000);
// Blackboard should have this Message:
bb.printMessages(std::cout);
// check for it:
// Try expunge, this should delete the message from poster PostTestMV:
m->tryExpunge();
bb.printMessages(std::cout);
// try again, this time nothing should be returned anymore:
// post same message type:
m->tryPost();
// make sure all callbacks are completed to avoid clashing in printing messages
usleep(300000);
// Blackboard should only have most recent Message:
bb.printMessages(std::cout);
// done
bb.fedstop();
NRT_DEBUG("Execution successful.");
}
catch (...) { nrt::warnAndRethrowException(); }
return 0;
}