iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tests/test-split-messages.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 <nrt/External/cereal/types/string.hpp>
#include <nrt/External/cereal/types/map.hpp>
#include <nrt/External/cereal/types/memory.hpp>
#include <iostream>
#include <fstream>
#include <tuple>
// BEGIN_NRT_CODE_SNIPPET splitmsg1.C
namespace mydata
{
NRT_DECLARE_MESSAGEFIELD(x, int, "x coordinate (pixels)");
NRT_DECLARE_MESSAGEFIELD(y, float, "y coordinate (feet)");
NRT_DECLARE_MESSAGEFIELD(s, std::string, "string info");
typedef typename std::map<int, std::string> mymap; // pre-processor parsing sucks, use typedefs for types that contain commas, etc
NRT_DECLARE_MESSAGEFIELD(m, mymap, "map stuff");
};
// END_NRT_CODE_SNIPPET
// BEGIN_NRT_CODE_SNIPPET splitmsg2.C
class MyMessage : public nrt::CompositeMessage<NRT_MESSAGEFIELD(mydata::x),
NRT_MESSAGEFIELD(mydata::y),
NRT_MESSAGEFIELD(mydata::s),
NRT_MESSAGEFIELD(mydata::m)>
{ };
// END_NRT_CODE_SNIPPET
// BEGIN_NRT_CODE_SNIPPET splitmsg4.C
namespace mydata2
{
NRT_DECLARE_MESSAGEFIELD(z, int, "z coordinate (pixels)");
NRT_DECLARE_MESSAGEFIELD(md, MyMessage, "my data");
}
class MyMessage2 : public nrt::CompositeMessage<NRT_MESSAGEFIELD(mydata2::z),
NRT_MESSAGEFIELD(mydata2::md)>
{ };
// END_NRT_CODE_SNIPPET
// ######################################################################
// BEGIN_NRT_CODE_SNIPPET splitmsg5.C
namespace mymod
{
NRT_DECLARE_MESSAGEPOSTER_PORT(Output, MyMessage, void, "MyMessage Output");
NRT_DECLARE_MESSAGEPOSTER_PORT(Output2, MyMessage2, void, "MyMessage2 Output");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(Input, MyMessage, void, "MyMessage Input");
NRT_DECLARE_MESSAGESUBSCRIBER_PORT(Input2, MyMessage2, void, "MyMessage2 Input");
}
class MyModule : public nrt::Module,
public nrt::MessagePoster<mymod::Output, mymod::Output2>,
public nrt::MessageSubscriber<mymod::Input, mymod::Input2>
{
public:
MyModule(std::string const & instanceid = "") : nrt::Module(instanceid)
{
// split our posters:
mymod::Output::createSubPosters();
mymod::Output2::createSubPosters();
// can also split port via string access. Necessary for our sub-ports and their subs:
nrt::Blackboard::instance().splitMessagePoster(uid().str(), "Output2.md");
// some split subscribers:
mymod::Input2::createSubSubscribers();
nrt::Blackboard::instance().splitMessageSubscriber(uid().str(), "Input2.md");
}
void onMessage(mymod::Input::InPtr msg)
{
std::stringstream ss;
for (auto const & m : msg->m()) { ss << "m[" << m.first << "]=[" << m.second << "] "; }
NRT_INFO("Got a MyMessage! x=[" << msg->x() << "], y=[" << msg->y() << "], s=[" << msg->s() << "], " << ss.str());
}
void onMessage(mymod::Input2::InPtr msg)
{
std::stringstream ss;
for (auto const & m : msg->md().m()) { ss << "m[" << m.first << "]=[" << m.second << "] "; }
NRT_INFO("Got a MyMessage2! x=[" << msg->md().x() << "], y=[" << msg->md().y() << "], s=[" << msg->md().s() <<
"], " << ss.str() << " z=[" << msg->z() << ']');
}
void tryPost()
{
NRT_INFO("Posting MyMessage");
std::unique_ptr<MyMessage> md(new MyMessage());
mymod::Output::post(md);
NRT_INFO("Posting MyMessage2");
std::unique_ptr<MyMessage2> md2(new MyMessage2());
mymod::Output2::post(md2);
}
};
// ######################################################################
namespace mymod2
{
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputX, nrt::Message<int>, void, "int Output");
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputY, nrt::Message<float>, void, "float Output");
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputZ, nrt::Message<int>, void, "int Output 2");
typedef typename std::map<int, std::string> mymap;
NRT_DECLARE_MESSAGEPOSTER_PORT(OutputM, nrt::Message<mymap>, void, "map Output 2");
}
class MyModule2 : public nrt::Module,
public nrt::MessagePoster<mymod2::OutputX, mymod2::OutputY, mymod2::OutputS, mymod2::OutputZ,
mymod2::OutputM>
{
public:
MyModule2(std::string const & instanceid = "") : nrt::Module(instanceid)
{ }
void tryPost()
{
// note: posting each part will block the poster until the whole message is assembled. Hence here to post each
// member one after the other from the same thread, we hold on to the poster results so we won't block on them:
NRT_INFO("all right, posting int to OutputX");
std::unique_ptr<nrt::Message<int> > mx(new nrt::Message<int>(42));
auto rx = mymod2::OutputX::post(mx);
NRT_INFO("all right, posting float to OutputY");
std::unique_ptr<nrt::Message<float> > my(new nrt::Message<float>(43.0F));
auto ry = mymod2::OutputY::post(my);
NRT_INFO("all right, posting string to OutputS");
std::unique_ptr<nrt::Message<std::string> > ms(new nrt::Message<std::string>("NRT Rocks!"));
auto rs = mymod2::OutputS::post(ms);
NRT_INFO("all right, posting int to OutputZ");
std::unique_ptr<nrt::Message<int> > mz(new nrt::Message<int>(44));
auto rz = mymod2::OutputZ::post(mz);
NRT_INFO("all right, posting std::map to OutputM");
std::unique_ptr<nrt::Message<mymod2::mymap> > mm(new nrt::Message<mymod2::mymap>());
mm->value()[1] = "NRT";
mm->value()[5] = "Rocks!";
auto rm = mymod2::OutputM::post(mm);
}
};
// END_NRT_CODE_SNIPPET
// ######################################################################
// ######################################################################
// ######################################################################
//! Test main function demonstrating use of Blackboard
int main(int argc, char const* argv[])
{
// BEGIN_NRT_CODE_SNIPPET splitmsg3.C
std::unique_ptr<MyMessage> msg(new MyMessage);
msg->x() = 23;
msg->y() = 42.0F;
msg->s() = "Hello";
msg->m()[12] = "twelve";
// END_NRT_CODE_SNIPPET
try
{
// BEGIN_NRT_CODE_SNIPPET splitmsg6.C
// Get a handle onto our Blackboard:
// Set some default args, in particular, we are master by default:
bb.setParamVal("master", true);
// Pass command-line args to Blackboard:
bb.setCommandLineArgs(argc, argv);
// Create some modules:
auto m = bb.addModule<MyModule>("mymodule");
auto m2 = bb.addModule<MyModule2>("mymodule2");
// get started:
bb.launch();
// set some topics: Module m2 is going to post its individual fields:
bb.setMessagePosterTopic(m2->uid().str(), "OutputX", "splita");
bb.setMessagePosterTopic(m2->uid().str(), "OutputY", "splita");
bb.setMessagePosterTopic(m2->uid().str(), "OutputS", "splita");
bb.setMessagePosterTopic(m2->uid().str(), "OutputZ", "splitb");
bb.setMessagePosterTopic(m2->uid().str(), "OutputM", "splita");
// and we set the topic filters on Input2 of Module m accordingly:
bb.setMessageSubscriberTopicFilter(m->uid().str(), "Input2.md.x", "splita");
bb.setMessageSubscriberTopicFilter(m->uid().str(), "Input2.md.y", "splita");
bb.setMessageSubscriberTopicFilter(m->uid().str(), "Input2.md.s", "splita");
bb.setMessageSubscriberTopicFilter(m->uid().str(), "Input2.md.m", "splita");
bb.setMessageSubscriberTopicFilter(m->uid().str(), "Input2.z", "splitb");
bb.printInfo(std::cout);
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);
// post a bunch of splits
m2->tryPost();
// make sure all callbacks are completed to avoid clashing in printing messages
usleep(300000);
// Blackboard should have this Message:
bb.printMessages(std::cout);
// done
bb.stop();
NRT_DEBUG("Execution successful.");
// END_NRT_CODE_SNIPPET
}
catch (...) { nrt::warnAndRethrowException(); }
return 0;
}