iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Component.H
Go to the documentation of this file.
1 /*! @file
2  @author Randolph Voorhies
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 #ifndef INCLUDE_NRT_CORE_MODEL_COMPONENT_H
36 #define INCLUDE_NRT_CORE_MODEL_COMPONENT_H
37 
39 #include <boost/thread.hpp>
40 #include <string>
41 #include <vector>
42 #include <map>
43 #include <unordered_map>
44 #include <future>
45 
47 
48 namespace nrt
49 {
50  class Manager;
51  class Module;
52  class ModuleBase;
53  class Blackboard;
54 
55  /*! \defgroup component Model components, parameters, manager, and associated classes
56 
57  These classes define how a complex model with parameters can be built from components.
58 
59  \ingroup core */
60 
61  // ######################################################################
62  //! A component of a model hierarchy.
63  /*! Model Components form the heart of every NRT application, as their main purpose is to allow a uniform interface
64  for tunable Parameters. In fact, every class which needs to expose parameters to the user should inherit directly
65  or inderectly from Component.
66 
67  Components typically form a Component Hierarchy with a Manager at the top, and a tree of sub-Components below. To
68  form this tree, just use the addSubComponent method to add some children, and then add some children to that
69  child, etc...
70 
71  Components are brought into action in several phases:
72 
73  - Construction: In constructors, Parameter values have not been set yet so nothing that depends on them should be
74  initialized yet. Typically, constructors should only initialize fixed component resources which are independent
75  of Parameter values, or they can also set default values for parameters, which may later be overriden by
76  command-line arguments.
77 
78  - initialization: When init() is called on the manager, it will parse any command-line arguments and set
79  Parameters accordingly, and it will then propagate down the entire component hierarchy. For each component,
80  preInit() will be called first (and can be overloaded in derived Components), then init() will propagate to
81  sub-components, and then postInit() will be called (and can be overloaded). Initialization is very similar to
82  construction and is rarely used, the exception being for components that wish to initialize/free some resource
83  even though they are not freshly constructed or about to be destructed yet, but they cannot rely on Parameter
84  values being set yet. During initialization, some Parameter values may not have been set yet and thus Parameters
85  should not be used. The init state is more relevant to Modules than raw Components: after init(), messages can
86  already flow, in particular messages related to changing parameter values on remote modules, setting topics,
87  etc. Before init, setting a Parameter value or setting a topic on a Module's port will not trigger a
88  (time-consuming) update of the Blackboard federation, so remote blackboards and modules would not know yet about
89  the parameter or topic value. They will know about it once init state is entered, though, so in general it is
90  recommended that you set all your parameters and topics before init(), as setting them after init() will trigger
91  potentially time-consuming Blackboard federation updates, recomputation of poster/subscriber topic matches, etc.
92  Note that parsing command-line arguments and setting Parameter values accordingly happens in the preInit() of
93  the Manager, so by the time init() propagates down to other Components this can be assumed to have been
94  completed.
95  After init() is completed, initialized() returns true; in more details:
96  - in preInit() initialized() does not yet return true;
97  - when subcomponent init() functions are called, parent initialized() is not yet true;
98  - initialized() then turns true;
99  - postInit() is called.
100 
101  - start: When start() is called on the manager, it will propagate down the entire component hierarchy. For each
102  component, preStart() will be called first (and can be overloaded in derived Components), then start() will
103  propagate to sub-components, and then postStart() will be called (and can be overloaded). By the time
104  preStart() is called, one can assume that all Parameters now have their final values, and Parameter-dependent
105  resources can be allocated/started. In preStart(), subcomponents are not started yet, so you should assume that
106  their paramaters are not fixed yet. In postStart(), all sub-components have been started and you can assume that
107  their parameter values are finalized and their resources allocated/started. Note that if start() is called and
108  init() has not been called yet, init() will automatically be called first.
109  After start() is completed, started() returns true.
110  - in preStart() started() does not yet return true;
111  - when subcomponent start() functions are called, parent started() is not yet true;
112  - started() then turns true;
113  - postStart() is called.
114  If in doubt, overload postStart() and allocate your Parameter-dependent resources in there.
115 
116  - launch: After completion of the recursive start() call on the Manager, all Components are in started() state and
117  upon calling launch() the Manager will now recurse through the Component tree again and call the run() function,
118  if any, on each component in turn, each in its own parallel thread. Note that there is no preLaunch() /
119  postLaunch() here as the run() function is available instead. If launch is called before start(), it will
120  automatically call start() first. For basic users, this is the only function you only need to call, i.e.,
121  instantiate all your components and get them ready, then simply call launch() on the manager to get your model
122  cranking. After launch(), running() will return true. More specifically, a two-stage process is triggered:
123  - Subcomponents are launched first, and they are switched to running state;
124  - then running() becomes true;
125  - then the run() functions of sub-components (if any) are started in parallel threads
126  - finally the run() function (if any) is started in a parallel tread.
127  Note for Module objects (see Module.H), which derive from Component: You cannot post() or check() until the
128  system is running(), attempting to do so will drop your messages. Indeed, in preInit(), prestart(), etc
129  components are busy setting up and not all resources necessary for operation may be instantiated yet. This thus
130  provides the following guarantee: it is safe in preStart(), postStart(), preStop(), postStop() to assume that
131  all Parameter values are finalized and that no Message is flowing. Thus, this is where you should
132  allocate/de-allocate all resources that depend on Parameter values. For example, a Component that holds an
133  internal queue whose size can be set by the user via a Parameter should instantiate the queue during preStart()
134  or postStart() (the choice here depends on whether sub-modules will need the queue or not), and should
135  de-allocate the queue during preStop() or postStop(). It is guaranteed that no onMessage() callback will be
136  triggered during these operations, so it is un-necessary in your onMessage() function to check whether the queue
137  is already here, etc. you can assume it's here if you instantiate/de-allocate it as recommended here.
138 
139  - wait: run() functions may voluntarily decide that they are done, e.g., for a source Component when there is no
140  more data to be sourced. Calling wait() on the manager will block until all run() functions thus exit.
141 
142  - stop: This is the dual of start(), with preStop() and postStop() following the same logic as preStart() and
143  postStart(). Note that we do not pre-empt and interrupt any run() function here, so it is up to the programmer
144  of each run() function to test periodically within the run() function whether running() is still true, and, if
145  not, to exit the run() function. Beware that stop() will block until run() has exited, so do indeed make sure
146  you check for running() an finish your run() function after running() has turned false.
147  Specific order is:
148  - running() turns to false
149  - we wait for the run() function to complete, and propagate any exception that may be discovered;
150  - preStop() is called (note that started() is still true at this point);
151  - stop() is called on all subcomponents;
152  - started() turns to false;
153  - postStop() is called.
154  If in doubt, overload postStop() and de-allocate your Parameter-dependent resources in there.
155 
156  - uninit: This is the dual of init(), with preUninit() and postUninit() following the same logic as preInit() and
157  postInit(). Specific order is:
158  - preUninit() is called (note that initialized() is still true at this point);
159  - uninit() is called on all subcomponents;
160  - initialized() turns to false;
161  - postUninit() is called.
162  - destruction.
163 
164  See \link test-Component.C \endlink for examples.
165 
166  \see ComponentSetupFunc
167  \ingroup component */
168  class Component : public virtual ParameterRegistry
169  {
170  public:
171  //protected: // FIXME inherited constructor does not compile if protected!
172  //! Constructor
173  /*! The standard way to create a component is via Component::addSubComponent() or Manager::addComponent(), rather
174  than constructing them by hand. Components constructed via the constructor (e.g., calling operator new) will
175  not be attached to a Component hierarchy.
176 
177  \param instanceName A string identifying a particular instance of a Component. This instance name should be
178  passed in through your derived Component's constructor, allowing users to disambiguate between multiple
179  instances of your Component. If the instance name is empty or NRT_AUTO_#, the actual instance will be names
180  NRT_AUTO_# with # replaced by a number. The final name is accessible via Component::meta().instance once your
181  component is constructed. There is no default value for instanceName in the base class to catch derived
182  classes that forgot to pass it down to the base, but it may be a good idea to set an empty string default to
183  instanceName in derived classes. */
184  Component(std::string const & instanceName);
185 
186  //! Prepare for deletion: uninit and disconnect from our parent
187  /*! Normal users do not need to call this, the destructor automatically does. */
188  void prepareForDeletion();
189 
190  //! Virtual destructor for safe inheritance
191  /*! Calls stop() if this module is started, and then uninit() if it is initialized. */
192  virtual ~Component();
193 
194  //! @name Component hierarchies
195  //! @{
196 
197  //! Pseudo-constructor: construct and add another component as a subcomponent of this one
198  /*! A child component of type Comp (which must derive from nrt::Component) will be created and added as a
199  sub-component of this. The child logically "belongs" to this component, and will automatically be deleted when
200  the parent component is deleted. In addition to construction, adding a subcomponent has the following effects:
201 
202  - subComp will be start()ed after this Component's preStart() but before this Component's postStart(), and idem
203  for init().
204 
205  - subComp will be stop()ed after this Component's preStop() but before this Component's postStop(), idem for
206  uninit().
207 
208  - When setting parameters, the sub-Component can be referenced as a child of this component. For instance, if
209  we have a ComponentParent which has ComponentChild as a sub-Component, and ComponentChild has parameter named
210  coolChildParam, then that parameter could be specified on the command line by
211  @code
212  --ComponentParent:ComponentChild:coolChildParam="whatever"
213  @endcode */
214  template <class Comp>
215  std::shared_ptr<Comp> addSubComponent(std::string const & instanceName = "");
216 
217  //! Remove a sub-Component from this Component, by shared_ptr
218  /*! \note Beware that the passed shared_ptr is invalidated in the process. A warning is issued if the use_count is
219  not down to zero after that (i.e., there are additional shared_ptr pointers to this Component floating around,
220  which prevent it from actually being deleted. */
221  template <class Comp>
222  void removeSubComponent(std::shared_ptr<Comp> & component);
223 
224  //! Remove a sub-Component from this Component, by instance name
225  void removeSubComponent(std::string const & instanceName);
226 
227  //! Get a sub-component by instance name
228  /*! This method does a dynamic_pointer_cast to Comp if it is not the default (nrt::Component). Throws if component
229  is not found by instance name, or it is found but not of type Comp (if Comp is specified). Note that once you
230  hold a shared_ptr to a Component, it is guaranteed that the component will not be destroyed until that
231  shared_ptr is released. If the NRT system tries to destroy the component (e.g., someone calls
232  removeSubComponent()), the component will be un-initialized and its parent will be unset, so it will not be
233  fully operational and will be actually deleted when the last shared_ptr to it runs out of scope. */
234  template <class Comp = nrt::Component>
235  std::shared_ptr<Comp> getSubComponent(std::string const & instanceName) const;
236 
237  //! Returns true if this component is top-level, i.e., its parent is an nrt::Manager (including nrt::Blackboard)
238  bool isTopLevel() const;
239 
240  //! @}
241 
242  //! @name Component runtime
243 
244  //! @{
245 
246  //! Has this component been initialized yet?
247  bool initialized() const;
248 
249  //! Is this component started, i.e., it has passed the start() state and not yet entered the stop() state.
250  bool started() const;
251 
252  //! Is this component running, i.e., has passed start() and been launch()ed and not yet entered the stop() state
253  bool running() const;
254 
255  //! Wait until all run() functions decide on their own that they are finished
256  /*! This differs from stop() in that stop() will set running() to false, which proper run() functions should
257  periodically check for and quit if running() has turned false. In addition, run() functions may also decide to
258  terminate on their own, e.g., in an ImageSource when there are no more frames. In such case, one should call
259  wait() here as a substitute for a while(1) loop in main(). */
260  void wait();
261  //! @}
262 
263  //! @name Component metainfo-related functions
264  //! @{
265 
266  //! Meta-info about a Component derived class
267  struct MetaInfo
268  {
269  //! Constructor
270  MetaInfo(std::string const & instancename);
271 
272  //! The C++ class name of the Component
273  std::string className;
274 
275  //! The instance name of the Component
276  std::string instanceName;
277 
278  //! A concatenation of the className and instanceName
279  std::string const str() const;
280 
281  //! Comparison
282  bool operator==(MetaInfo const& m) const;
283  };
284 
285  //! Get the metainfo of this Component
286  /*! \note Always use meta() and not itsMetaInfo, because meta() will guarantee that the class name is set. */
287  Component::MetaInfo const & meta() const;
288 
289  //! @}
290 
291  /*! @name Component Parameter-related functions
292 
293  Each Component can hold Parameter objects (through inheritance) that can be set externally by users to modify
294  the operation of the Component. */
295  //! @{
296 
297  //! Set a parameter value
298  /*! Throws if we don't have a parameter by that name or the value does not work out. Here is how the descriptor
299  works:
300 
301  The basic format is
302 
303  @code
304  [Classname-Instancename]:[...]:[paramname]
305  @endcode
306 
307  If you only specify paramname, then the param must exist in this component. If you specify a bunch of
308  Classname-Instancename, then we will look for that param in a subcomponent. Note that Classname-Instancename
309  is a loose requirement, you could have just the Classname (possibly with namespaces, subclass, etc in which
310  case use :: as in C++), or just the Instancename, or both separated by a '-'. When parsing it we look for the
311  first '-', and if there is none we try to match against either Classname or Instancename of the component,
312  while if there is one or more we try to match Classname-Instancename or also just Instancename (in case your
313  instance name contains dashes too). This is robust except in the funky situation where your instance name has
314  a dash in it and the word before the dash happens to match your class name, so just avoid that (eg, <i>avoid
315  dashes and class names in your instance names</i>).
316 
317  Now that <code>[Classname-Instancename]</code> token can also be replaced by a *, which is equivalent to any
318  number of any Classname-Instancename specifications. So use the * to reach parameters when you don't know how
319  deep they are. If there is some other Classname-Instancename between a * and the final paramname, then
320  recursion is turned off and anything between the * and paramname must match intervening components/instances.
321 
322  For example,
323 
324  @code
325  MyInst:*:CoolClass:MyParam
326  @endcode
327 
328  would match parameters where MyInst matches the top-level component (the one on which you call setParamVal()),
329  then would recurse through any number of subcomponents, until one of them matches CoolClass, and then we would
330  look for MyParam parameter in that subcomponent, and we would not look any deeper. You may want to play with
331  test-Component to try different scenarios.
332 
333  Finally note that there is an implicit first *: that is automatically prepended to your description, so if you
334  just specify a paramname and nothing else before it, we will set all params by that name in all subcomponents
335  no matter how deep they are (as if you had specified *:paramname).
336 
337  @throws nrt::exception::ParameterException if no Parameter matches the given descriptor.
338  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
339  guaranteed to have at least one element since we throw if no matching parameter is found. */
340  template <typename T>
341  std::vector<std::string> setParamVal(std::string const & paramdescriptor, T const & val);
342 
343  //! Set a parameter value, simple version assuming only one parameter match
344  /*! This calls setParamVal(), and checks that exactly one match was found.
345  @throws nrt::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
346  template <typename T>
347  void setParamValUnique(std::string const & paramdescriptor, T const & val);
348 
349  //! Get parameter(s) value(s) by descriptor
350  /*! Use this method to get the current value of a Component's parameter from the string descriptor. Values for all
351  parameters that match the descriptor are returned.
352 
353  For example, if the class MyComponent has an integer parameter named "myparam" you could get the
354  value like so:
355 
356  @code
357  std::shared_ptr<MyComponent> comp(new MyComponent);
358  auto paramValues = comp->getParamVal<int>("myparam");
359  for (auto const & pp : paramValues) NRT_INFO("Parameter " << pp.first << " = " << pp.second);
360  @endcode
361 
362  @throws nrt::exception::ParameterException if no Parameter matches the given descriptor.
363  @return list of <paramdescriptor, value> for all parameters that matched the given descriptor. The list is
364  guaranteed to have at least one element since we throw if no matching parameter is found.
365 
366  \see setParamVal for a detailed explanation of the paramdescriptor */
367  template <typename T>
368  std::vector<std::pair<std::string, T> > getParamVal(std::string const & paramdescriptor) const;
369 
370  //! Get a parameter value, simple version assuming only one parameter match
371  /*! This calls getParamVal(), checks that exactly one match was found, and returns its value.
372  For example, if the class MyComponent has an integer parameter named "myparam" you could get the
373  value like so:
374 
375  @code
376  std::shared_ptr<MyComponent> comp(new MyComponent);
377  int paramValue = comp->getUniqueParamVal<int>("myparam");
378  @endcode
379 
380  @throws nrt::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
381  template <typename T>
382  T getParamValUnique(std::string const & paramdescriptor) const;
383 
384  //! Set a parameter value, by string
385  /*! \see setParamVal for a detailed explanation of the paramdescriptor
386  @throws nrt::exception::ParameterException if no Parameter matches the given descriptor or if the
387  given string cannot be converted to the Parameter's native type.
388  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
389  guaranteed to have at least one element since we throw if no matching parameter is found. */
390  std::vector<std::string> setParamString(std::string const & paramdescriptor, std::string const & val);
391 
392  //! Set a parameter value by string, simple version assuming only one parameter match
393  /*! This calls setParamVal(), and checks that exactly one match was found.
394  @throws nrt::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
395  void setParamStringUnique(std::string const & paramdescriptor, std::string const & val);
396 
397  //! Get a parameter value, by string
398  /*! \see setParamVal for a detailed explanation of the paramdescriptor
399  Use this method to get the current value of a Component's parameter from the string descriptor. Values for all
400  parameters that match the descriptor are returned, as string.
401  @throws nrt::exception::ParameterException if no Parameter matches the given descriptor.
402  @return list of <paramdescriptor, valuestring> for all parameters that matched the given descriptor. The list
403  is guaranteed to have at least one element since we throw if no matching parameter is found. */
404  std::vector<std::pair<std::string, std::string> > getParamString(std::string const & paramdescriptor) const;
405 
406  //! Get a parameter value by string, simple version assuming only one parameter match
407  /*! This calls getParamVal(), checks that exactly one match was found, and returns its value as a string.
408  @throws nrt::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
409  std::string getParamStringUnique(std::string const & paramdescriptor) const;
410 
411  //! Get our full descriptor (including all parents) as [Classname-Instancename]:[...]:[...]
412  std::string descriptor() const;
413 
414  //! Get the ModuleUID (as string) of this Component's nearest parent Module, or an empty string
415  std::string parentModuleUID() const;
416 
417  //! Produce a nice textual hierarchy of this Component's sub-tree
418  void prettyPrintTree(std::ostream & os, int indent = 0) const;
419 
420  //! Return a list of parameter summaries for a given descriptor
421  /*! \see setParamVal for a detailed explanation of the paramdescriptor. This is like getParamString() but returns
422  parameter summaries instead of just values. */
423  std::vector<std::pair<std::string, nrt::ParameterSummary> >
424  getParamSummary(std::string const & paramdescriptor) const;
425 
426  //! Return a list of parameter summaries for all parameters of this Component and its subcomponents
427  /*! This just aggregates the summaries for all parameters of the component and (recursively) its subcomponents
428  (possibly restricting to only sub-components that are not of Module type; in such case it is assumed that one
429  would call this function on each Module in a collection). The results are indexed by unrolled parameter
430  descriptor, as in getParamString(). */
431  std::vector<std::pair<std::string, nrt::ParameterSummary> >
432  getParamSummary(bool skipsubmodules = false) const;
433 
434  //! @}
435 
436  /*! @name Component path-related functions
437 
438  Each Component can keep track of a preferred filesystem path. Typically, users should not tamper with this,
439  but Module objects (which derive from Component) that are dynamically loaded will have that path set to the
440  path where the Module's shared object file (.so) was found. This allows those modules to access some of their
441  local configuration data, which may, for example, be stored in an \c etc/ directory under the module path. */
442  //! @{
443 
444  //! Assign a filesystem path to this component
445  void setPath(std::string const & path);
446 
447  //! If given path is relative (not starting with /), prepend the Component path to it; otherwise, no-op
448  std::string absolutePath(std::string const & path);
449 
450  //! @}
451 
452  protected:
453  //! @name Component setup functions overloadable by derived classes
454 
455  //! @{
456 
457  //! Called before all sub-Components are init()ed
458  virtual void preInit() { }
459 
460  //! Called after all sub-Components are init()ed
461  virtual void postInit() { }
462 
463  //! Called before all sub-Components are start()ed
464  virtual void preStart() { }
465 
466  //! Called after all sub-Components are start()ed
467  virtual void postStart() { }
468 
469  //! Called in its own thread after all Components have been start()ed
470  /*! If your Component has some work to do at runtime, you can put that functionality into the run() function.
471  Every Component's run() method will be spawned in a new thread as soon as the start() process has
472  completed. In run(), you should periodically test whether running() is true, and, if not, that means that
473  stop() has been called and you should then exit the run() function as soon as practical.
474 
475  So the typical form of a run() function is as follows:
476  @code
477  void MyComponent::run()
478  {
479  // Do one-time things that require us to be running(), for example, post some one-time message, etc
480 
481  // Loop while we are still running. Make sure that your loop is relatively fast, as if it takes a long time,
482  // users will have to wait for it when they attempt to stop a running system. In particuler, beware of
483  // blocking on producer/consumer queues, waiting for I/O, etc and make sure you use functions with timeouts
484  // for these kinds of things.
485  while (running())
486  {
487  // do a bunch of things like, e.g., read some data from a device and post it
488  }
489 
490  // Do final cleanups, e.g., close resources opened before our while loop
491  }
492  @endcode */
493  virtual void run() { }
494 
495  //! Called before all sub-Components are stop()ed
496  virtual void preStop() { }
497 
498  //! Called after all sub-Components are stop()ed
499  virtual void postStop() { }
500 
501  //! Called before all sub-Components are uninit()ed
502  virtual void preUninit() { }
503 
504  //! Called after all sub-Components are uninit()ed
505  virtual void postUninit() { }
506 
507  //! @}
508 
509  //! @name Component misc protected functions
510  //! @{
511 
512  //! This method is called by a Parameter when it has been changed. Users should never overload this method.
513  virtual void notifyParamChanged(nrt::ParameterState const state, ParameterBase const * const param) const;
514 
515  public:
516  //! This method is called by the Blackboard to refresh a ParamChangedListener
517  virtual void notifyAllParamChanged(nrt::ParameterState const state) const;
518 
519  //! Recursively get all param summaries
520  virtual void getAllParamSummaries(std::vector<nrt::ParameterSummary> & ps) const;
521 
522  protected:
523  // Storage for sub-Components
524  std::vector<std::shared_ptr<Component> > itsSubComponents;
525 
526  // Mutex to protect our list of subcomponents
527  mutable boost::shared_mutex itsSubMtx;
528 
529  // A "shadow variable" used for distributed logging.
530  /* If you're reading this documentation, you should never need to touch this! */
531  Component * const nrt_component_this;
532 
533  // Recursively populate a list of parameters, for help message
534  void populateHelpMessage(std::string const & cname,
535  std::unordered_map<std::string /* categ+categdesc */,
536  std::unordered_map<std::string /* name+defaultval+validvals+descrip */,
537  std::vector<std::pair<std::string /* component */, std::string /* value */ > > > > &
538  helplist) const;
539 
540  //! Create a message port for a Parameter of this Component (or sub-Component)
541  /*! Requires initialized() or more because you need to be able to post(), check(), etc by the time you create
542  ports for your parameter.
543  @throws nrt::exception::ParameterException if the parameter is not found.
544  @return list of param descriptors that matched. */
545  //std::vector<std::string>
546  //createParamPort(ModuleParamPort const ptype, std::string const & module, std::string const & descriptor);
547 
548  //! Delete a message port for a Parameter of this Component (or sub-Component)
549  /*! Note that we will automatically delete the ports during uninit() because they cannot be allowed to exist and
550  post(), check(), etc if we are not initialized.
551  @throws nrt::exception::ParameterException if the port is not found, eg, it has not been created.
552  @return list of param descriptors that matched. */
553  //std::vector<std::string>
554  //deleteParamPort(ModuleParamPort const ptype, std::string const & descriptor);
555 
556  //! Set the topic of a Parameter Poster
557  /*! \pre Requires initialized() or more.
558  @throws nrt::exception::ParameterException if the poster is not found, eg, it has not been created. */
559  //std::vector<std::string>
560  //setParamPosterTopic(std::string const & descriptor, std::string const & topic);
561 
562  //! Set the topic filter of a Parameter Checker
563  /*! \pre Requires initialized() or more.
564  @throws nrt::exception::ParameterException if the checker is not found, eg, it has not been created. */
565  //std::vector<std::string>
566  //setParamCheckerTopicFilter(std::string const & descriptor, std::string const & topicfilt);
567 
568  //! Set the topic filter of a Parameter Subscriber
569  /*! \pre Requires initialized() or more.
570  @throws nrt::exception::ParameterException if the subscriber is not found, eg, it has not been created. */
571  //std::vector<std::string>
572  //setParamSubscriberTopicFilter(std::string const & descriptor, std::string const & topicfilt);
573 
574  //! @}
575 
576  friend class ParameterBase;
577  template <typename T> friend class ParameterCore;
578  friend class GenericLogger;
579  friend class Manager;
580  //! Allow Blackboard to access our step-by-step runstate functions directly
581  friend class Blackboard;
582 
583  //! Mutex used to protect our internals other than subcomponents and parameters
584  mutable boost::shared_mutex itsMtx;
585 
586  private:
587  //! Initialization
588  /* Invoke: runPreInit(), then setInitialized(), finally runPostInit() */
589  virtual void init();
590 
591  //! Recursively run preInit()
592  void runPreInit();
593 
594  //! Recursively set initialized flag
595  void setInitialized();
596 
597  //! Recursively run postInit()
598  void runPostInit();
599 
600  //! Starts the component, and its subtree, recursively
601  /* Invoke: runPreStart(), then setStarted(), finally runPostStart() */
602  virtual void start();
603 
604  //! Recursively run preStart()
605  void runPreStart();
606 
607  //! Recursively set started flag
608  void setStarted();
609 
610  //! Recursively run postStart()
611  void runPostStart();
612 
613  //! Launch the run() function, and propagate to subcomponents
614  /*! This async's run() and then propagates to subscomponents. */
615  virtual void launch();
616 
617  //! First part of the launch process: turn running() to true on everyone recursively
618  void initiatelaunch();
619 
620  //! Second part of the launch process: start each run() function in a new thread, recursively
621  void completelaunch();
622 
623  //! Switch out of running state and then call waitendrun() to wait for all run() threads to complete
624  virtual void endrun();
625 
626  //! Switch running() to false, should only be called from within endrun()
627  void initiateendrun();
628 
629  //! Wait for all run() threads to complete, should only be called from within endrun()
630  void completeendrun();
631 
632  //! Stops the component and its subtree, recursively
633  /* Invoke: runPreStop(), then setStopped(), finally runPostStop() */
634  virtual void stop();
635 
636  //! Recursively run preStop()
637  void runPreStop();
638 
639  //! Recursively unset started flag
640  void setStopped();
641 
642  //! Recursively run postStop()
643  void runPostStop();
644 
645  //! Un-initialize
646  /* Invoke: runPreUninit(), then setUninitialized(), finally runPostUninit() */
647  virtual void uninit();
648 
649  //! Recursively run preUninit()
650  void runPreUninit();
651 
652  //! Recursively set uninitialized flag
653  void setUninitialized();
654 
655  //! Recursively run postUninit()
656  void runPostUninit();
657 
658  // The future that will block until run() terminates
659  std::future<void> itsRunFuture;
660 
661  // Our className and instanceName
662  // Programmer note: always use meta() to access this, even inside Component, as the first call to meta() will
663  // finish constructing the MetaInfo, which is incomplete initially
664  MetaInfo itsMetaInfo;
665 
666  // Has this Component been launched?
667  volatile bool itsRunning;
668 
669  // Has this Component been started?
670  volatile bool itsStarted;
671 
672  // Has this Component been initialized?
673  volatile bool itsInitialized;
674 
675  // The Component which contains this one as a sub-Component - this may be NULL if the component is not part of any
676  // hierarchy, or is the manager.
677  Component * itsParent;
678 
679  bool matchTokenToComponent(std::string const & token) const;
680  void findParamAndActOnIt(std::string const & descriptor,
681  std::function<void(nrt::ParameterBase * param, std::string const & unrolled)> doit,
682  std::function<bool()> empty) const;
683  void findParamAndActOnIt(std::vector<std::string> const & descrip, bool recur, size_t idx,
684  std::string const & unrolled,
685  std::function<void(nrt::ParameterBase *, std::string const &)> doit) const;
686  /*
687  int createDeleteParamPort(ModuleParamPort const ptype, std::string const & module, std::string const & descriptor,
688  std::vector<std::string> const & descrip, bool const create, size_t idx);
689  int setParamPortTopi(ModuleParamPort const ptype, std::vector<std::string> const & descrip,
690  std::string const & topi, size_t idx);
691  */
692  void getParamSummary(std::vector<std::pair<std::string, nrt::ParameterSummary> > & ret,
693  bool skipsubmodules, std::string const & unrolled) const;
694 
695  std::string itsPath; // filesystem path assigned to this Component, empty by default
696 
697  //! Helper function to compute an automatic instance name, if needed
698  /*! If the given instanceName is empty or "NRT_AUTO_#" then a new name will be returned of the form NRT_AUTO_#
699  where # is replaced by a unique number among all our sub-components. Otherwise, the original instance name
700  passed in is just returned. */
701  std::string computeInstanceName(std::string const & instance) const;
702  };
703 } //nrt
704 
705 // Include inlined implementation details that are of no interest to the end user
707 
708 #endif // INCLUDE_NRT_CORE_MODEL_COMPONENT_H
709