iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
test-Module.C
Go to the documentation of this file.
1 /*! @file
2  @author Laurent Itti
3  @copyright GNU Public License (GPL v3)
4  @section License
5  @verbatim
6  // ////////////////////////////////////////////////////////////////////////
7  // The iLab Neuromorphic Robotics Toolkit (NRT) //
8  // Copyright 2010-2012 by the University of Southern California (USC) //
9  // and the iLab at USC. //
10  // //
11  // iLab - University of Southern California //
12  // Hedco Neurociences Building, Room HNB-10 //
13  // Los Angeles, Ca 90089-2520 - USA //
14  // //
15  // See http://ilab.usc.edu for information about this project. //
16  // ////////////////////////////////////////////////////////////////////////
17  // This file is part of The iLab Neuromorphic Robotics Toolkit. //
18  // //
19  // The iLab Neuromorphic Robotics Toolkit is free software: you can //
20  // redistribute it and/or modify it under the terms of the GNU General //
21  // Public License as published by the Free Software Foundation, either //
22  // version 3 of the License, or (at your option) any later version. //
23  // //
24  // The iLab Neuromorphic Robotics Toolkit is distributed in the hope //
25  // that it will be useful, but WITHOUT ANY WARRANTY; without even the //
26  // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
27  // PURPOSE. See the GNU General Public License for more details. //
28  // //
29  // You should have received a copy of the GNU General Public License //
30  // along with The iLab Neuromorphic Robotics Toolkit. If not, see //
31  // <http://www.gnu.org/licenses/>. //
32  // ////////////////////////////////////////////////////////////////////////
33  @endverbatim */
34 
35 
37 #include <nrt/Core/Model/Manager.H>
38 #include <nrt/Core/Typing/Macros.H> // for NRT_MACRO_WHERE
39 #include <nrt/Core/Geometry/Dims.H>
40 #include <iostream>
41 
42 class MessageA : public nrt::MessageBase {
43  public:
44  template<class Archive> inline void serialize(Archive& ar) { }
45 };
46 
47 class MessageB : public nrt::MessageBase {
48  public:
49  template<class Archive> inline void serialize(Archive& ar) { }
50 };
51 
52 class MessageC : public nrt::MessageBase {
53  public:
54  template<class Archive> inline void serialize(Archive& ar) { }
55 };
56 
57 class MessageD : public nrt::MessageBase {
58  public:
59  template<class Archive> inline void serialize(Archive& ar) { }
60 };
61 
62 
63 NRT_DECLARE_MESSAGEPOSTER_PORT(OutputA, MessageA, void, "MessageA Output");
64 NRT_DECLARE_MESSAGEPOSTER_PORT(OutputB, MessageB, void, "MessageB Output");
65 NRT_DECLARE_MESSAGEPOSTER_PORT(OutputCraw, MessageC, MessageA, "MessageC Output, raw data");
66 NRT_DECLARE_MESSAGEPOSTER_PORT(OutputCfilt, MessageC, MessageA, "MessageC Output, filtered data");
67 NRT_DECLARE_MESSAGEPOSTER_PORT(PostTestMM, MessageA, MessageB, "PostTest<MessageA, MessageB>");
68 NRT_DECLARE_MESSAGEPOSTER_PORT(PostTestMV, MessageA, void, "PostTest<MessageA, void>");
69 
70 NRT_DECLARE_MESSAGECHECKER_PORT(AsyncInputA, MessageA, "MessageA Async Input");
71 NRT_DECLARE_MESSAGECHECKER_PORT(AsyncInputC, MessageC, "MessageC Async Input");
72 
73 NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputA, MessageA, void, "MessageA Input");
74 NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputCleft, MessageC, MessageA, "MessageC Input, Left side");
75 NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputCright, MessageC, MessageA, "MessageC Input, Right side");
76 NRT_DECLARE_MESSAGESUBSCRIBER_PORT(SubscriTestMM, MessageA, MessageB, "SubscriTest<MessageA, MessageB>");
77 NRT_DECLARE_MESSAGESUBSCRIBER_PORT(SubscriTestMV, MessageA, void, "SubscriTest<MessageA, void>");
78 
79 NRT_DECLARE_PARAMETER(dims, nrt::Dims<int>, "Dimensions to use", nrt::Dims<int>());
80 
81 // ######################################################################
82 //! What you derive from determines what you will be allowed to do when interacting with the Blackboard
83 class MyModule : public nrt::Module,
84  public nrt::MessagePoster<OutputA, OutputB, OutputCraw, OutputCfilt, PostTestMM, PostTestMV>,
85  public nrt::MessageChecker<AsyncInputA, AsyncInputC>,
86  public nrt::MessageSubscriber<InputA, InputCleft, InputCright, SubscriTestMM, SubscriTestMV>,
87  public nrt::Parameter<dims>
88 {
89  public:
90  // ######################################################################
91  //! Example constructor with instanceID
92  MyModule(std::string const & instanceid = "") : nrt::Module(instanceid) { }
93 
94  // ######################################################################
95  //! Example post()
96  void tryPost()
97  {
98  NRT_INFO("START: Testing post() functionality");
99 
100  // can use: post(MessageA):
101  std::unique_ptr<MessageA> m(new MessageA);
102  NRT_INFO("Posting MessageA...");
103  OutputA::post(m); // this blocks until all callbacks are complete
104  NRT_INFO("Done posting MessageA.");
105 
106  // can use: post(MessageB):
107  std::unique_ptr<MessageB> m2(new MessageB);
108  NRT_INFO("Posting MessageB...");
109  if (auto r = OutputB::post(m2)) r.waitgetall();
110  NRT_INFO("Done posting MessageB.");
111 
112  // can use: post(MessageC): simpler syntax
113  auto m3 = OutputCraw::make_message(); // make_message could take args and forward them to message constructor
114  NRT_INFO("Posting MessageC...");
115  OutputCraw::PostResultsType res = OutputCraw::post(m3);
116  NRT_INFO("Done posting MessageC.");
117 
118  // once posted, a message is gone (the unique_ptr has been reset to nullptr):
119  if (m3) NRT_FATAL("Posted Message not stolen!");
120 
121  // cannot use post(MessageD) since we don't derive from MessagePoster<MessageD>:
122  std::unique_ptr<MessageD> m4(new MessageD);
123  //OutputD::post(m4); // error: no matching function
124 
125  // wait until our post of MessageC has completed all callbacks. Beware that res may be null if there were no
126  // matching callbacks:
127  if (res) res.waitgetall();
128  NRT_INFO("Done with results of MessageC post.");
129 
130 
131  // more tests...
132  std::unique_ptr<MessageA> ptmm(new MessageA);
133  PostTestMM::post(ptmm);
134  std::unique_ptr<MessageA> ptmv(new MessageA);
135  PostTestMV::post(ptmv);
136 
137  NRT_INFO("DONE: Testing post() functionality");
138  }
139 
140  // ######################################################################
141  //! Example check()
143  {
144  NRT_INFO("START: Testing check() functionality");
145 
146  // can use: AsyncInputA::check()
147  if (nrt::MessageCheckerResults<MessageA> res = AsyncInputA::check(mcp)) {
148  // use the results...
149  while(res.exhausted() == false)
150  try
151  {
152  auto msg = res.get();
153  if (msg) NRT_INFO("Got a result from check()!");
154  }
156  NRT_WARNING(" Received Blackboard exception from check() -- PROPAGATING IT");
157  throw;
158  // Note that if you are not going to handle the exception, no need to catch it here, can just skip this
159  // entire catch statement, the Blackboard will build a recursive stack trace automatically...
160  } catch (nrt::exception::ModuleException & e) {
161  NRT_WARNING(" Received Module exception from check() -- PROPAGATING IT");
162  throw;
163  // Note that if you are not going to handle the exception, no need to catch it here, can just skip this
164  // entire catch statement, the Blackboard will build a recursive stack trace automatically...
165  } catch (...) {
166  NRT_WARNING(" Received unknown exception from check()! Re-throwing it.");
167  throw; // or we could just throw a ModuleException instead if we want perfect forwarding over the network
168  }
169  }
170  else NRT_DEBUG("No MessageA on the Blackboard");
171 
172  NRT_INFO("DONE: Testing check() functionality");
173  }
174 
175  // ######################################################################
176  void tryExpunge()
177  {
178  NRT_INFO("START: Testing expunge() functionality");
179  PostTestMV::expunge();
180  NRT_INFO("DONE: Testing expunge() functionality");
181  }
182 
183  // ######################################################################
184  //! Message callback for MessageA
185  virtual void onMessage(InputA::InPtr msg)
186  { NRT_DEBUG("serving MessageA"); }
187 
188  // ######################################################################
189  //! Message callback for MessageC (first callback)
190  virtual std::unique_ptr<MessageA> onMessage(InputCleft::InPtr msg)
191  {
192  NRT_DEBUG("serving MessageC, left side");
193  return std::unique_ptr<MessageA>(new MessageA);
194  }
195 
196  // ######################################################################
197  //! Message callback for MessageC (second callback)
198  // example of simpled syntax
199  virtual InputCright::OutPtr onMessage(InputCright::InPtr msg)
200  {
201  NRT_DEBUG("serving MessageC, right side");
202  return InputCright::make_return_message(); // make_return_message could forward args to message constructor
203  }
204 
205  // ######################################################################
206  //! Message callback for SubscriTestMM
207  virtual std::unique_ptr<MessageB> onMessage(SubscriTestMM::InPtr msg)
208  {
209  NRT_DEBUG("serving SubscriTestMM");
210  return std::unique_ptr<MessageB>(new MessageB);
211  }
212 
213  // ######################################################################
214  //! Message callback for SubscriTestMV
215  virtual void onMessage(SubscriTestMV::InPtr msg)
216  {
217  NRT_DEBUG("serving SubscriTestMV");
218  }
219 };
220 
221 // ######################################################################
222 // ######################################################################
223 // ######################################################################
224 // Test of namespaces, connectors
225 class MessageZ : public nrt::MessageBase {
226  public:
227  template<class Archive> inline void serialize(Archive& ar) { }
228 };
229 
230 NRT_DECLARE_MESSAGEPOSTER_PORT(OutputZ, MessageZ, void, "MessageZ Output");
231 NRT_DECLARE_MESSAGECHECKER_PORT(AsyncInputZ, MessageZ, "MessageZ Async Input");
232 NRT_DECLARE_MESSAGESUBSCRIBER_PORT(InputZ, MessageZ, void, "MessageZ Input");
233 
234 class TestModule : public nrt::Module,
235  public nrt::MessagePoster<OutputZ>,
236  public nrt::MessageChecker<AsyncInputZ>,
237  public nrt::MessageSubscriber<InputZ>
238 {
239  public:
240  TestModule(std::string const & instanceid = "") : nrt::Module(instanceid) { }
241 
242  virtual ~TestModule() { }
243 
244  virtual void onMessage(InputZ::InPtr msg) { NRT_DEBUG("serving MessageZ"); }
245 };
246 
247 // ######################################################################
248 // ######################################################################
249 // ######################################################################
250 //! Test main function demonstrating use of Blackboard
251 int main(int argc, char const* argv[])
252 {
253  try
254  {
255  // Get a handle onto our Blackboard:
257 
258  // Set some default args, in particular, we are master by default:
259  bb.setParamVal("master", true);
260 
261  // Get command-line args:
262  bb.setCommandLineArgs(argc, argv);
263 
264  // Parse command line and get operational (configure network, etc):
265  bb.init();
266 
267  // Create some modules:
268  auto m = bb.addModule<MyModule>("My Module");
269 
270  // mess with namespace, topic, etc
271  m->setNamespace("CoolSpace");
272  m->InputA::setTopicFilter(".*");
273  m->AsyncInputA::setTopicFilter(".*");
274  m->SubscriTestMM::setTopicFilter(".*"); // need to investigate this
275 
276  // Build some complicated mess with a bunch of TestModule objects:
277  auto t1 = bb.addModule<TestModule>("t1");
278  auto t2 = bb.addModule<TestModule>("t2");
279  auto t3 = bb.addModule<TestModule>("t3");
280 
281  // t1 is in the root namespace
282  t1->OutputZ::setTopic("base topic of t1");
283  t1->InputZ::setTopicFilter("tap");
284 
285  // t2 is in a deep namespace
286  t2->setNamespace("ns1/ns2/ns3");
287 
288  // add a connector from ns1/ns2/ns3 to ns1/ns2
289  t2->OutputZ::make_connector("t2pc1", "ns1/ns2/ns3", nrt::ConnectorType::Border, ".*", "top");
290 
291  // add a connector from ns1/ns2 to ns1
292  t2->OutputZ::make_connector("t2pc2", "ns1/ns2", nrt::ConnectorType::Border, "top*", "tip");
293 
294  // add a connector from ns1 to root
295  t2->OutputZ::make_connector("t2pc3", "ns1", nrt::ConnectorType::Border, "tip+", "tap");
296 
297  // t3 in ns1/nsX
298  t3->setNamespace("ns1/nsX");
299  t3->OutputZ::setTopic("base topic of t3");
300  t3->InputZ::setTopicFilter(".*");
301  t3->AsyncInputZ::setTopicFilter(".*");
302 
303  // add a checker connector from ns1/nsX to ns1
304  t3->AsyncInputZ::make_connector("t3cc", "ns1/nsX", nrt::ConnectorType::Border, "tip", ".*");
305 
306  // add a subscriber connector from ns1/nsX to ns1
307  t3->InputZ::make_connector("t3sc", "ns1/nsX", nrt::ConnectorType::Border, "x", ".*");
308 
309  // add a subscriber connector from ns1/ns2 to ns1
310  t3->InputZ::make_connector("t3sc2", "ns1/ns2", nrt::ConnectorType::Border, "top", "x+");
311 
312  // soooo...
313  // t2::OutputZ should now be connected to t1::InputZ
314  // t3::AsyncInputZ should be connected to t2::OutputZ
315  // t3::InputZ should be connected to t2::OutputZ, actual connection is in ns1/ns2
316 
317  /* DISBALED FOR NOW...
318  // try to create some ports for our param:
319  m->createParamPort(nrt::ModuleParamPort::Poster, "dims");
320  m->createParamPort(nrt::ModuleParamPort::Checker, "dims");
321  m->createParamPort(nrt::ModuleParamPort::Subscriber, "dims");
322  m->createParamPort(nrt::ModuleParamPort::Subscriber, "dims"); // no problem
323  */
324 
325  // get started:
326  bb.fedlaunch();
327 
328  bb.printInfo(std::cout);
329 
330  // post a Message:
331  m->tryPost();
332 
333  // make sure all callbacks are completed to avoid clashing in printing messages
334  usleep(300000);
335 
336  // Blackboard should have this Message:
337  bb.printMessages(std::cout);
338 
339  // check for it:
341 
342  // Try expunge, this should delete the message from poster PostTestMV:
343  m->tryExpunge();
344  bb.printMessages(std::cout);
345 
346  // try again, this time nothing should be returned anymore:
348 
349  // post same message type:
350  m->tryPost();
351 
352  // make sure all callbacks are completed to avoid clashing in printing messages
353  usleep(300000);
354 
355  // Blackboard should only have most recent Message:
356  bb.printMessages(std::cout);
357 
358  // done
359  bb.fedstop();
360 
361  NRT_DEBUG("Execution successful.");
362  }
363  catch (...) { nrt::warnAndRethrowException(); }
364 
365  return 0;
366 }