source: finroc_plugins_composite_ports/tInterfaceBase.h @ 23:3c9cac2a0cc1

Last change on this file since 23:3c9cac2a0cc1 was 23:3c9cac2a0cc1, checked in by Max Reichardt <mreichardt@…>, 16 months ago

Adds 'interface modifiers' for customization of port composite interface creation (as there are diverse use cases). Refactors and tidies partial interface creation with this new feature.

File size: 19.5 KB
Line 
1//
2// You received this file as part of Finroc
3// A framework for intelligent robot control
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    plugins/composite_ports/tInterfaceBase.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2020-01-14
27 *
28 * \brief   Contains tInterfaceBase
29 *
30 * \b tInterfaceBase
31 *
32 * Generic base class for all port composite interface
33 *
34 */
35//----------------------------------------------------------------------
36#ifndef __plugins__structure__tInterfaceBase_h__
37#define __plugins__structure__tInterfaceBase_h__
38
39//----------------------------------------------------------------------
40// External includes (system with <>, local with "")
41//----------------------------------------------------------------------
42#include "core/port/tPortWrapperBase.h"
43#include "core/port/tPortGroup.h"
44
45//----------------------------------------------------------------------
46// Internal includes with ""
47//----------------------------------------------------------------------
48
49//----------------------------------------------------------------------
50// Namespace declaration
51//----------------------------------------------------------------------
52namespace finroc
53{
54
55//----------------------------------------------------------------------
56// Forward declarations / typedefs / enums
57//----------------------------------------------------------------------
58
59namespace structure
60{
61class tModule;
62class tSenseControlModule;
63}
64
65namespace composite_ports
66{
67namespace internal
68{
69template <int Tprimary_interface_relations, template <typename> class TPortType, typename T, bool Trpc, bool Tdirection_specified>
70class tGenericPortType;
71class tInterfaceFactory;
72}
73
74/*! Tag that marks component interfaces in which all ports should be instantiated below a single backend and in a uniform direction (e.g. for data recording) */
75extern const std::string cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION;
76
77
78//----------------------------------------------------------------------
79// Class declaration
80//----------------------------------------------------------------------
81//! Base class for port composite interface
82/*!
83 * Generic base class for all port composite interface.
84 */
85class tInterfaceBase : public core::tPortWrapperBase, public core::tAbstractPortCreationInfo::tModifier
86{
87
88//----------------------------------------------------------------------
89// Public methods and typedefs
90//----------------------------------------------------------------------
91public:
92
93  /*!
94   * Allows to specify type of primary port
95   * If set, this allows to instantiate interfaces partially
96   */
97  enum tPrimaryPortType
98  {
99    ANY,
100    CONTROLLER_PORT,
101    SENSOR_PORT
102  };
103
104  class tBackend;
105  typedef std::function<std::string(tBackend&, tBackend&)> tConnectFunction;  //!< First backend is data source primary backend, second backend is data destination primary backend
106  typedef core::tPortGroup* (*tCreateMissingComponentInterfaceFunction)(core::tFrameworkElement* parent, const core::tFrameworkElementFlags&);  //!< Flags are required flags of missing required interface
107
108  tInterfaceBase(tBackend* backend = nullptr) :
109    tPortWrapperBase(backend)
110  {}
111
112
113  void operator()(core::tAbstractPortCreationInfo& creation_info) const;
114
115  /*!
116   * \return Wrapped backend
117   */
118  tBackend* Backend()
119  {
120    return static_cast<tBackend*>(this->GetWrapped());
121  }
122  const tBackend* Backend() const
123  {
124    return static_cast<tBackend*>(this->GetWrapped());
125  }
126
127  /*!
128   * Connect interface to specified partner interface
129   *
130   * \param partner Interface to connect this interface to
131   * \param connect_options Any connect options to apply
132   * \return Pointer to connector object if connecting succeeded. nullptr otherwise.
133   * \throw Throws std::invalid_argument on invalid connect options
134   */
135  core::tConnector* ConnectTo(const tInterfaceBase& partner, const core::tConnectOptions& connect_options = core::tConnectOptions());
136  using tPortWrapperBase::ConnectTo;
137
138  /*!
139   * Searches for interfaces of specified type below parent element.
140   *
141   * \param parent Parent element below which to search for interface
142   * \param type Type of interface to search for
143   * \param skip_derived_interfaces By default subclasses of interfaces are also included. They are skipped if this parameter is true.
144   * \return Any interfaces found. Returns empty vector if type is not an interface type.
145   */
146  static std::vector<tInterfaceBase> FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces = false);
147
148  /*!
149   * \return Returns primary port type of interface type TInterface
150   */
151  template <typename TInterface>
152  static tPrimaryPortType GetPrimaryPortType()
153  {
154    tInterfaceTypeData result;
155    TInterface temp_instance("", &result);
156    return result.primary_port_type;
157  }
158
159  /*!
160   * \return Returns interface id for interface type TInterface
161   */
162  template <typename TInterface>
163  static rrlib::rtti::tType GetType()
164  {
165    tInterfaceTypeData result;
166    TInterface temp_instance("", &result);
167    return result.type;
168  }
169
170  /*!
171   * \param element Element to check
172   * \return Whether provided framework element is a port composite interface
173   */
174  static inline bool IsInterface(core::tFrameworkElement& element)
175  {
176    enum { cRELEVANT_FLAGS = (core::tFrameworkElementFlag::PORT | core::tFrameworkElementFlag::COMPOSITE_PORT).Raw() };
177    return (element.GetAllFlags().Raw() & cRELEVANT_FLAGS) == cRELEVANT_FLAGS;
178  }
179
180  /*!
181   * Sets config entries for any parameters (backend) in this interface
182   *
183   * \param config_entry Parent node in configuration tree that parameters are configured from
184   */
185  void SetConfigEntry(const rrlib::uri::tPath& config_entry);
186
187  class tBackend : public core::tAbstractPort
188  {
189    //----------------------------------------------------------------------
190    // Public methods
191    //----------------------------------------------------------------------
192  public:
193
194    /*!
195     * (Primary backend constructor)
196     *
197     * \param interface_type Interface type
198     * \param parent_component Parent as passed to tInterface constructor (typically component)
199     * \param parent Parent framework element of primary backend
200     * \param primary_relation_id Relation ID to primary port type of root interface
201     * \param name Name of interface (must be unique in parent interfaces)
202     * \param convenience_port Whether port type below this backend is a convenience port type
203     * \param custom_connect_function Custom connect function for this interface
204     * \param create_missing_component_interface_function Function to create missing component interface
205     * \param primary_port_type Type of ports with relation id zero
206     * \param partial_interface Whether to instantiate a partial interface (this parameter is merged with scoped extra constructor parameters)
207     */
208    tBackend(const rrlib::rtti::tType& interface_type, core::tFrameworkElement* parent_component, core::tFrameworkElement* parent, int primary_relation_id, const std::string& name, bool convenience_port, const tConnectFunction& custom_connect_function = tConnectFunction(), tCreateMissingComponentInterfaceFunction create_missing_component_interface_function = nullptr, tPrimaryPortType primary_port_type = tPrimaryPortType::ANY, bool partial_interface = false);
209
210    /*!
211     * \return All backends that make up this port composite interface. The 'primary' backend is at index zero.
212     */
213    const std::vector<tBackend*>& AllBackends() const
214    {
215      return primary_backend.all_backends;
216    }
217
218    /*!
219     * Convenience method for connect functions (including custom ones)
220     * Connects all child ports of this and the provided backend that have the same name
221     *
222     * \param destination Second backend
223     * \param connect_options Any connect options to apply
224     */
225    void ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options = core::tConnectOptions());
226
227    /*!
228     * \param generic_port_backend Whether backend is a generic port (-> unspecified whether input or output)
229     * \return Default port flags for ports below this backend
230     */
231    core::tFrameworkElementFlags GetDefaultPortFlags(bool generic_port_backend) const;
232
233    /*!
234     * \return Whether this interface is a partial interface
235     */
236    bool IsPartialInterface() const
237    {
238      return partial_interface;
239    }
240
241    /*!
242     * \return Whether this is the primary backend
243     */
244    bool IsPrimaryBackend() const
245    {
246      return &primary_backend == this;
247    }
248
249    /*!
250     * \return Type of ports with relation id zero (as specified in constructor)
251     */
252    tPrimaryPortType PrimaryPortType() const
253    {
254      return primary_port_type;
255    }
256
257    //----------------------------------------------------------------------
258    // Protected methods
259    //----------------------------------------------------------------------
260  protected:
261
262    virtual void OnConnect(tAbstractPort& partner, bool partner_is_destination) override;
263
264    virtual void OnDisconnect(tAbstractPort& partner, bool partner_is_destination) override;
265
266    void OnInitialization() override;
267
268    void OnManagedDelete() override;
269
270    void SetFlag(tFlag flag, bool value = true)
271    {
272      core::tAbstractPort::SetFlag(flag, value);
273    }
274
275    //----------------------------------------------------------------------
276    // Private fields and methods
277    //----------------------------------------------------------------------
278  private:
279
280    friend class tInterfaceBase;
281    friend class internal::tInterfaceFactory;
282
283    template <int Tprimary_interface_relations, template <typename> class TPortType, typename T, bool Trpc, bool Tdirection_specified>
284    friend class internal::tGenericPortType;
285
286    template <template <typename> class TPort>
287    friend class tInterface;
288
289
290    /*! Parent as passed to tInterface constructor (typically component) */
291    core::tFrameworkElement* parent_component;
292
293    /*! Pointer to primary backend (for primary port type) */
294    tBackend& primary_backend;
295
296    /*!
297     * All backends that make up this port composite interface (first is relation id)
298     * The 'primary' backend is at index zero.
299     * It contains and manages the connections to other interfaces.
300     * This vector is only filled and maintained in the primary backend.
301     */
302    std::vector<tBackend*> all_backends;
303    std::vector<std::pair<int, tBackend*>> relation_backend_mapping;
304
305    /*! Custom connect function for this interface */
306    tConnectFunction custom_connect_function;
307
308    /*!
309     * Helper variable for e.g. initialization and deletion of all backends
310     * (only primary backend instance's version is valid)
311     */
312    bool operation_on_all_elements_pending = false;
313
314    /*! Whether port type below this backend is a convenience port type */
315    bool convenience_port_type;
316
317    /*! Relation ID to primary port type of root interface */
318    int primary_relation_id;
319
320    /*! Function to create missing component interface */
321    tCreateMissingComponentInterfaceFunction create_missing_component_interface_function;
322
323    /*! Type of ports with relation id zero */
324    tPrimaryPortType primary_port_type;
325
326    /*! Whether this interface is a partial interface (and if yes, whether partial instantiation should instantiate the primary port type ports (instead of the secondary))  */
327    bool partial_interface, partial_interface_primary_port_type;
328
329    /*!
330     * Constructor for secondary instances
331     */
332    tBackend(core::tAbstractPortCreationInfo& creation_info, tBackend& primary);
333
334    /*!
335     * (called by tGenericPortType)
336     * \param primary_relation_id Relation id to primary port type
337     * \return Whether port with this relation is an output (or client) port
338     */
339    bool CreateOutputPort(int primary_relation_id);
340
341    /*!
342     * Creates port (generic instantiation only)
343     * Called for all data and RPC ports to be created below port composite interface root.
344     * (Behavior of this function may be altered by modifier)
345     *
346     * \param creation_info Creation info to use.
347     * \param primary_relation_id Primary relation ID, as used in interface classes (zero is primary port type)
348     */
349    core::tAbstractPort* CreatePort(const core::tAbstractPortCreationInfo& creation_info, int primary_relation_id) const;
350
351    /*!
352     * (called by tGenericPortType)
353     * \param primary_relation_id Relation id to primary port type
354     * \return Backend with specified index
355     */
356    tBackend* GetBackend(int primary_relation_id);
357
358    /*!
359     * Defines which ports are part of partial instantiations.
360     * Partial instantiations either contain all ports of the primary type (+ all port types in the same direction) -
361     * or the secondary.
362     *
363     * \param primary_relation_id Relation id to primary port type
364     * \param partial_interface_variant_primary_port_type Whether partial instantiation should instantiate the primary port type ports (instead of the secondary)
365     * \return Whether ports with relation id are part of the specified variant
366     */
367    static bool IsPartOfPartialInstantiation(int primary_relation_id, bool partial_interface_variant_primary_port_type);
368  };
369
370//----------------------------------------------------------------------
371// Protected methods
372//----------------------------------------------------------------------
373protected:
374
375  static tBackend* CreateBackend(rrlib::rtti::tType interface_type, tInterfaceBase* parent, const std::string& name, tPrimaryPortType primary_port_type, const tConnectFunction& custom_connect_function, int primary_relation_id, bool convience_port_type);
376  static tBackend* CreateBackend(rrlib::rtti::tType interface_type, tInterfaceBase::tBackend* parent, const std::string& name, tPrimaryPortType primary_port_type, const tConnectFunction& custom_connect_function, int primary_relation_id, bool convience_port_type);
377
378  /*!
379   * \return Parent as passed to tInterface constructor (typically component)
380   */
381  inline core::tFrameworkElement* ParentComponent() const
382  {
383    return Backend() ? Backend()->parent_component : nullptr;
384  }
385
386  template <typename TParent>
387  static constexpr tCreateMissingComponentInterfaceFunction GetDefaultCreateMissingInterfaceFunction()
388  {
389    typedef typename std::conditional<std::is_base_of<structure::tModule, TParent>::value, ForModules, typename std::conditional<std::is_base_of<structure::tSenseControlModule, TParent>::value, ForSenseControlModules, ForOtherComponents>::type>::type tHelper;
390    return &tHelper::template CreateMissingInterface<>;
391  }
392
393  /*! Additional constructor parameters that are not passed through tInterface constructor - for convenience and backward-compatibility */
394  struct tExtraConstructorParameters
395  {
396    bool partial_interface = false;
397  };
398
399  class tScopedExtraConstructorParameters
400  {
401  public:
402
403    tScopedExtraConstructorParameters() :
404      parameters(nullptr)
405    {}
406
407    tScopedExtraConstructorParameters(tScopedExtraConstructorParameters && other) :
408      parameters(nullptr)
409    {
410      this->lock = std::move(other.lock);
411      std::swap(parameters, other.parameters);
412    }
413
414    tScopedExtraConstructorParameters& operator=(tScopedExtraConstructorParameters && other)
415    {
416      this->lock = std::move(other.lock);
417      std::swap(parameters, other.parameters);
418      return *this;
419    }
420
421    inline tExtraConstructorParameters* operator->()
422    {
423      return parameters;
424    }
425
426    static tScopedExtraConstructorParameters Get();
427
428    ~tScopedExtraConstructorParameters()
429    {
430      if (parameters)
431      {
432        *parameters = tExtraConstructorParameters();
433      }
434    }
435
436  private:
437
438    tScopedExtraConstructorParameters(rrlib::thread::tRecursiveMutex& mutex, tExtraConstructorParameters* parameters) :
439      lock(mutex),
440      parameters(parameters)
441    {}
442
443    rrlib::thread::tLock lock;
444    tExtraConstructorParameters* parameters;
445  };
446
447//----------------------------------------------------------------------
448// Private fields and methods
449//----------------------------------------------------------------------
450private:
451
452  template <template <typename> class TPort>
453  friend class tInterface;
454  friend class internal::tInterfaceFactory;
455
456  /*! Helper class to extract type info on interfaces */
457  struct tInterfaceTypeData
458  {
459    rrlib::rtti::tType type;
460    tPrimaryPortType primary_port_type;
461  };
462
463  struct ForOtherComponents
464  {
465    template <typename TParent = core::tFrameworkElement>
466    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
467    {
468      return nullptr;
469    }
470  };
471
472  struct ForModules
473  {
474    template <typename TParent = structure::tModule>
475    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
476    {
477      TParent* module = static_cast<TParent*>(parent);
478      if ((TParent::cINPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
479      {
480        return &module->GetInputs();
481      }
482      else if ((TParent::cOUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
483      {
484        return &module->GetOutputs();
485      }
486      else if (required_flags.Get(tFlag::PARAMETER_INTERFACE))
487      {
488        return &module->GetParameters();
489      }
490      else if (required_flags.Get(tFlag::INTERFACE_FOR_RPC_PORTS))
491      {
492        return &module->GetServices();
493      }
494      return nullptr;
495    }
496  };
497
498  struct ForSenseControlModules
499  {
500    template <typename TParent = structure::tSenseControlModule>
501    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
502    {
503      TParent* module = static_cast<TParent*>(parent);
504      if ((TParent::cSENSOR_INPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
505      {
506        return &module->GetSensorInputs();
507      }
508      else if ((TParent::cSENSOR_OUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
509      {
510        return &module->GetSensorOutputs();
511      }
512      if ((TParent::cCONTROLLER_INPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
513      {
514        return &module->GetControllerInputs();
515      }
516      else if ((TParent::cCONTROLLER_OUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
517      {
518        return &module->GetControllerOutputs();
519      }
520      else if (required_flags.Get(tFlag::PARAMETER_INTERFACE))
521      {
522        return &module->GetParameters();
523      }
524      else if (required_flags.Get(tFlag::INTERFACE_FOR_RPC_PORTS))
525      {
526        return &module->GetServices();
527      }
528      return nullptr;
529    }
530  };
531};
532
533//----------------------------------------------------------------------
534// End of namespace declaration
535//----------------------------------------------------------------------
536}
537}
538
539#endif
Note: See TracBrowser for help on using the repository browser.