iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Module.H
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 
36 #ifndef INCLUDE_NRT_CORE_BLACKBOARD_MODULE_H
37 #define INCLUDE_NRT_CORE_BLACKBOARD_MODULE_H
38 
39 // Define ModuleBase, Component, Blackboard and other helper classes not directly used by end-users
41 
42 #include <queue>
43 #include <list>
44 
45 namespace nrt
46 {
47  class Module; // defined below
48  template <class PortName, class Msg, class Ret> class MessagePosting; // see ModulePortHelpers.H
49  template <class PortName, class Msg> class MessageChecking; // see ModulePortHelpers.H
50  template <class PortName, class Msg, class Ret> class MessageSubscription; // see ModulePortHelpers.H
51 
52  // ######################################################################
53  /*! \defgroup module Module and poster/checker/subscriber ports
54 
55  Module is the basic computation unit in NRT. Modules have ports through which they can communicate with other
56  modules via Message objects.
57 
58  \ingroup blackboard */
59 
60  /*! @{ */ // **********************************************************************
61 
62  // ######################################################################
63  //! MessagePoster class
64  /*! This interface exposes a post() function for each Poster listed in the variadic template argument list. Each
65  element of the list must derive from nrt::MessagePoster<Msg, Ret, Description> with various types for Msg, Ret
66  and Description. Modules that wish to post() Message objects to the Blackboard must virtually derive from
67  MessagePoster as this is the only way to obtain post() access to the Blackboard. Canonical use example is:
68 
69  @code
70  NRT_DECLARE_MESSAGEPOSTER_PORT(OutputA, MessageA, void, "MessageA Output"); // Our Poster is named OutputA
71 
72  class MyModule : public nrt::Module, public nrt::MessagePoster<OutputA, MyOtherPoster, ...>
73  {
74  public:
75  void myMemberFunction() {
76  std::unique_ptr<MyMessageA> message(new MyMessageA());
77  nrt::MessagePosterResults<OutputA> result = OutputA::post(message);
78  // may wait on the result, check return values, catch exceptions, etc see class MessagePosterResults
79  }
80  }
81  @endcode */
82  template <class Poster, class ... Tail>
83  class MessagePoster<Poster, Tail ...> : public Poster, public MessagePoster<Tail ...>
84  {
85  static_assert(std::is_base_of<nrt::MessagePosterCoreBase, Poster>::value,
86  "nrt::MessagePoster<...> template arguments must all be MessagePoster ports "
87  "(derive from nrt::MessagePosterCoreBase). Make sure your template arguments passed to "
88  "MessagePoster<...> were created with NRT_DECLARE_MESSAGEPOSTER_PORT()");
89  };
90 
91  // ######################################################################
92  //! Module objects which derive from nrt::MessageChecker<Checking> will be allowed to check() for Message objects
93  /*! This interface exposes a check() function for the Checker's Message type. Modules that wish to check()
94  for Message objects to the Blackboard must virtually derive from MessageChecker, as this is the only way to obtain
95  check() access to the Blackboard.
96 
97  check() is a fast and inexpensive function if the only posters posting messages with matching message type,
98  namespace, and topic are local. It becomes a more expensive call if remote posters are known to possibly post
99  matching messages, as those need to be remotely checked for, and if found, serialized and transported back to the
100  checker over the network. In both cases, however, check() returns immediately, querying of remote Blackboards is
101  dispatched in parallel threads, and a MessageCheckerResults object is returned which contains future access to the
102  found messages, if any. Use message types, namespaces, and topics when building distributed systems to maximize
103  throughput and minimize network congestion.
104 
105  Canonical use example is as follows:
106 
107  @code
108  NRT_DECLARE_MESSAGECHECKER_PORT(AsyncInputA, MessageA, "MessageA Async Input");
109 
110  class MyModule : public nrt::Module, public nrt::MessageChecker<AsyncInputA, MyOtherChecker, ...>
111  {
112  public:
113  void myMemberFunction() {
114  nrt::MessageCheckerResults<MessageA> result = AsyncInputA::check();
115  // may wait on the result, check returned messages, catch exceptions, etc see class MessageCheckerResults
116  }
117  }
118  @endcode */
119  template <class Checker, class ... Tail>
120  class MessageChecker<Checker, Tail ...> : public Checker, public MessageChecker<Tail ...>
121  {
122  static_assert(std::is_base_of<nrt::MessageCheckerCoreBase, Checker>::value,
123  "nrt::MessageChecker<...> template arguments must all be MessageChecker ports "
124  "(derive from nrt::MessageCheckerCoreBase). Make sure your template arguments passed to "
125  "MessageChecker<...> were created with NRT_DECLARE_MESSAGECHECKER_PORT()");
126  };
127 
128  // ######################################################################
129  //! Module objects which derive from nrt::MessageSubscriber<Subscriber> will subscribe to matching Posters
130  /*! This interface exposes an onMessage() callback function for the Message type and return type of the
131  Subscriber. Module objects that virtually derive from MessageSubscriber will see their onMessage() function called
132  back by the Blackboard each time a relevant Message is post()'ed, either locally or by a remote poster. Classes
133  deriving from nrt::MessageSubscriber<Subscriber> must implement the onMessage() pure virtual function. Note that
134  onMessage() is defined deeper (in MessageSubscriberCore), and takes the following syntax:
135 
136  @code
137  virtual typename Subscriber::RetPtr onMessage(Subscriber::InPtr msg) = 0;
138  @endcode
139 
140  This onMessage() function must be implemented by Module objects which derive from
141  MessageSubscriber<Subscriber>.
142 
143  To allow perfect forwarding of exceptions, designers of onMessage() functions should take care to only throw
144  nrt::exception::ModuleException, or possibly forward any caught nrt::exception::BlackboardException (e.g., if you
145  post() something within your onMessage()::InPtr function). Indeed, if any other exception is thrown, it will be
146  caught by the Blackboard but will then be wrapped into an nrt::exception::ModuleException which will not be very
147  descriptive to the recipient. The reason for this is that we must know how to serialize exceptions so that we can
148  send them back to remote posters, which we cannot do in general but we can do for nrt::exception::ModuleException
149  and nrt::exception::BlackboardException. */
150  template <class Subscriber, class ... Tail>
151  class MessageSubscriber<Subscriber, Tail ...> : public Subscriber, public MessageSubscriber<Tail ...>
152  {
153  static_assert(std::is_base_of<nrt::MessageSubscriberCoreBase, Subscriber>::value,
154  "nrt::MessageSubscriber<...> template arguments must all be MessageSubscriber ports "
155  "(derive from nrt::MessageSubscriberCoreBase). Make sure your template arguments passed to "
156  "MessageSubscriber<...> were created with NRT_DECLARE_MESSAGECHECKER_PORT()");
157 
158  public:
159  //! Allow host class to access all the right onMessage() functions of MessageSubscriber
160  using Subscriber::onMessage;
161  };
162 
163  // ######################################################################
164  // ######################################################################
165  //! Base class for a Module
166  /*! User modules should derive from nrt::Module and from any of nrt::MessagePoster, nrt::MessageChecker,
167  nrt::MessageSubscriber depending on what they post(), check() for, or subscribe to.
168 
169  Be sure to issue a:
170 
171  @code
172  NRT_REGISTER_MODULE(ModuleClassName);
173  @endcode
174 
175  in your .C file after you have defined a new Module, to make sure that your module, once compiled as a shared
176  object file, can be loaded at runtime (e.g., by the nrtLoader).
177 
178  See \link test-Module.C \endlink for examples. */
179  class Module : public nrt::Component, public virtual nrt::ModuleBase
180  {
181  public:
182  //! Constructor
183  Module(std::string const & instanceid = "");
184 
185  //! Virtual destructor for safe inheritance
186  virtual ~Module();
187 
188  //! Set the module's namespace
189  /*! The module must be a top-level module, i.e., its parent is the Blackboard), otherwise throws. This call
190  propagates to all sub-modules recursively, enforcing that all sub-modules are in the same namespace as their
191  top-level parent module. */
192  void setNamespace(std::string const & namespac);
193 
194  //! If old namespace matches ours, then change ours to new namespace; otherwise, do nothing
195  /*! Note that partial matches are allowed at the start of the names, which allows renaming a namespace. You can
196  only call changeNamespace() on a top-level module, i.e., its parent is the Blackboard), otherwise throws. This
197  call propagates to all sub-modules recursively, enforcing that all sub-modules are in the same namespace as
198  their top-level parent module. */
199  void changeNamespace(std::string const & oldnamespc, std::string const & newnamespc);
200 
201  //! Create a message port for a Parameter of this module (or sub-Component or sub-Module)
202  /*! \note You must be at least initialized() for this to work, because you need to be able to post(), check(),
203  etc by the time you create ports for your parameter.
204  \note When creating a ModuleParamPort::Poster, this method will immediately post the current Parameter
205  value. */
206  //std::vector<std::string>
207  //createParamPort(ModuleParamPort const ptype, std::string const & descriptor);
208 
209  //! Delete a message port for a Parameter of this module (or sub-Component or sub-Module)
210  /*! Note that we will automatically delete the ports during uninit() because they cannot be allowed to exist and
211  post(), check(), etc if we are not initialized. */
212  //std::vector<std::string>
213  //deleteParamPort(ModuleParamPort const ptype, std::string const & descriptor);
214 
215  //! Set the topic of a Parameter Poster
216  /*! Will throw if the poster is not found, eg, it has not been created. Requires initialized() or more.
217  \note After setting the topic, this method will immediately post the current Parameter value.
218  @throws nrt::exception::ParameterException if no Parameter matches the given descriptor or if one is found
219  but no poster port has been created for it.
220  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
221  guaranteed to have at least one element since we throw if no matching parameter is found. */
222  //std::vector<std::string>
223  //setParamPosterTopic(std::string const & descriptor, std::string const & topic);
224 
225  //! Set the topic filter of a Parameter Checker
226  /*! Will throw if the checker is not found, eg, it has not been created. Requires initialized() or more.
227  @throws nrt::exception::ParameterException if no Parameter matches the given descriptor or if one is found
228  but no poster port has been created for it.
229  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
230  guaranteed to have at least one element since we throw if no matching parameter is found. */
231  //std::vector<std::string>
232  //setParamCheckerTopicFilter(std::string const & descriptor, std::string const & topicfilt);
233 
234  //! Set the topic filter of a Parameter Subscriber
235  /*! Will throw if the subscriber is not found, eg, it has not been created. Requires initialized() or more.
236  @throws nrt::exception::ParameterException if no Parameter matches the given descriptor or if one is found
237  but no poster port has been created for it.
238  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
239  guaranteed to have at least one element since we throw if no matching parameter is found. */
240  //std::vector<std::string>
241  //setParamSubscriberTopicFilter(std::string const & descriptor, std::string const & topicfilt);
242 
243 
244  //! Pseudo-constructor: construct and add another Module as a submodule of this one
245  /*! A child module of type Mod (which must derive from nrt::Module) will be created and added as a
246  sub-module of this. The child logically "belongs" to this module, and will automatically be deleted when
247  the parent module is deleted. In addition to construction, adding a submodule has the following effects:
248 
249  - subMod will be start()ed after this Module's preStart() but before this Module's postStart(), and idem
250  for init().
251 
252  - subMod will be stop()ed after this Module's preStop() but before this Module's postStop(), idem for
253  uninit().
254 
255  - When setting parameters, the sub-Module can be referenced as a child of this module. For instance, if
256  we have a ModuleParent which has ModuleChild as a sub-Module, and ModuleChild has parameter named
257  coolChildParam, then that parameter could be specified on the command line by
258  @code
259  --ModuleParent:ModuleChild:coolChildParam="whatever"
260  @endcode
261 
262  This method is essentially the same as nrt::Component::addSubComponent() except that it enforces that Mod
263  derives from nrt::Module and it registers the Module with the local Blackboard, sets its namespace, and
264  updates the Blackboard Federation. */
265  template <class Mod>
266  std::shared_ptr<Mod> addSubModule(std::string const & instanceName = "");
267 
268  //! Remove a sub-Module from this Module, by shared_ptr
269  /*! \note Beware that the passed shared_ptr is invalidated in the process. A warning is issued if the use_count is
270  not down to zero after that (i.e., there are additional shared_ptr pointers to this Module floating around,
271  which prevent it from actually being deleted. */
272  template <class Mod>
273  void removeSubModule(std::shared_ptr<Mod> & module);
274 
275  //! Remove a sub-Module from this Module, by instance name
276  void removeSubModule(std::string const & instanceName);
277 
278  //! Get a sub-module by instance name
279  /*! This method does a dynamic_pointer_cast to Mod if it is not the default (nrt::Module). Throws if module
280  is not found by instance name, or it is found but not of type Mod (if Mod is specified). Note that once you
281  hold a shared_ptr to a Module, it is guaranteed that the module will not be destroyed until that
282  shared_ptr is released. If the NRT system tries to destroy the module (e.g., someone calls
283  removeSubModule()), the module will be un-initialized and its parent will be unset, so it will not be
284  fully operational and will be actually deleted when the last shared_ptr to it runs out of scope. */
285  template <class Mod = nrt::Module>
286  std::shared_ptr<Mod> getSubModule(std::string const & instanceName) const;
287 
288  protected:
289  //! Notification when a param is changed
290  virtual void notifyParamChanged(nrt::ParameterState const state, ParameterBase const * const param) const;
291 
292  private:
293  void doSetNamespace(std::string const & namespac);
294  void doChangeNamespace(std::string const & oldnamespc, std::string const & newnamespc);
295  };
296 
297  //! Convenience macro to define a Poster using CRTP
298  /*! \def NRT_DECLARE_MESSAGEPOSTER_PORT(PortName, MsgType, RetType, Description)
299  \hideinitializer
300  Use this macro to define a posting. \see MessagePoster */
301 
302  //! Convenience macro to define a Checker using CRTP
303  /*! \def NRT_DECLARE_MESSAGECHECKER_PORT(PortName, MsgType, Description)
304  \hideinitializer
305  Use this macro to define a checking. \see MessageChecker */
306 
307  //! Convenience macro to define a Subscription using CRTP
308  /*! \def NRT_DECLARE_MESSAGESUBSCRIBER_PORT(PortName, MsgType, RetType, Description)
309  \hideinitializer
310  Use this macro to define a subscription. \see MessageSubscription */
311 
312  /*! @} */ // **********************************************************************
313 
314 }; // namespace nrt
315 
316 // Include implementation details of no interest to end users
318 
319 #endif // INCLUDE_NRT_CORE_BLACKBOARD_MODULE_H