source: finroc_plugins_composite_ports/tInterfaceBase.h @ 22:e2e8d05ef4e4

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

Cleanly implements the details of creating service ports in partially instantiated port composite interfaces.

File size: 18.4 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 * \param type Data type to check
79 * \return Is specified data type a port composite interface type?
80 */
81inline bool IsInterfaceType(const rrlib::rtti::tType& type)
82{
83  return type.GetTypeClassification() == rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE;
84}
85
86
87//----------------------------------------------------------------------
88// Class declaration
89//----------------------------------------------------------------------
90//! Base class for port composite interface
91/*!
92 * Generic base class for all port composite interface.
93 */
94class tInterfaceBase : public core::tPortWrapperBase, public core::tAbstractPortCreationInfo::tModifier
95{
96
97//----------------------------------------------------------------------
98// Public methods and typedefs
99//----------------------------------------------------------------------
100public:
101
102  /*!
103   * Allows to specify type of primary port
104   * Is set, this allows to instantiate interfaces partially
105   */
106  enum tPrimaryPortType
107  {
108    ANY,
109    CONTROLLER_PORT,
110    SENSOR_PORT
111  };
112
113  class tBackend;
114  typedef std::function<std::string(tBackend&, tBackend&)> tConnectFunction;  //!< First backend is data source primary backend, second backend is data destination primary backend
115  typedef core::tPortGroup* (*tCreateMissingComponentInterfaceFunction)(core::tFrameworkElement* parent, const core::tFrameworkElementFlags&);  //!< Flags are required flags of missing required interface
116
117  tInterfaceBase(tBackend* backend = nullptr) :
118    tPortWrapperBase(backend)
119  {}
120
121
122  void operator()(core::tAbstractPortCreationInfo& creation_info) const;
123
124  /*!
125   * \return Wrapped backend
126   */
127  tBackend* Backend()
128  {
129    return static_cast<tBackend*>(this->GetWrapped());
130  }
131  const tBackend* Backend() const
132  {
133    return static_cast<tBackend*>(this->GetWrapped());
134  }
135
136  /*!
137   * Connect interface to specified partner interface
138   *
139   * \param partner Interface to connect this interface to
140   * \param connect_options Any connect options to apply
141   * \return Pointer to connector object if connecting succeeded. nullptr otherwise.
142   * \throw Throws std::invalid_argument on invalid connect options
143   */
144  core::tConnector* ConnectTo(const tInterfaceBase& partner, const core::tConnectOptions& connect_options = core::tConnectOptions());
145  using tPortWrapperBase::ConnectTo;
146
147  /*!
148   * Searches for interfaces of specified type below parent element.
149   *
150   * \param parent Parent element below which to search for interface
151   * \param type Type of interface to search for
152   * \param skip_derived_interfaces By default subclasses of interfaces are also included. They are skipped if this parameter is true.
153   * \return Any interfaces found. Returns empty vector if type is not an interface type.
154   */
155  static std::vector<tInterfaceBase> FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces = false);
156
157  /*!
158   * \return Returns primary port type of interface type TInterface
159   */
160  template <typename TInterface>
161  static tPrimaryPortType GetPrimaryPortType()
162  {
163    tInterfaceTypeData result;
164    TInterface temp_instance("", &result);
165    return result.primary_port_type;
166  }
167
168  /*!
169   * \return Returns interface id for interface type TInterface
170   */
171  template <typename TInterface>
172  static rrlib::rtti::tType GetType()
173  {
174    tInterfaceTypeData result;
175    TInterface temp_instance("", &result);
176    return result.type;
177  }
178
179  /*!
180   * \param element Element to check
181   * \return Whether provided framework element is a port composite interface
182   */
183  static inline bool IsInterface(core::tFrameworkElement& element)
184  {
185    enum { cRELEVANT_FLAGS = (core::tFrameworkElementFlag::PORT | core::tFrameworkElementFlag::COMPOSITE_PORT).Raw() };
186    return (element.GetAllFlags().Raw() & cRELEVANT_FLAGS) == cRELEVANT_FLAGS;
187  }
188
189  /*!
190   * Sets config entries for any parameters (backend) in this interface
191   *
192   * \param config_entry Parent node in configuration tree that parameters are configured from
193   */
194  void SetConfigEntry(const rrlib::uri::tPath& config_entry);
195
196  class tBackend : public core::tAbstractPort
197  {
198    //----------------------------------------------------------------------
199    // Public methods
200    //----------------------------------------------------------------------
201  public:
202
203    /*!
204     * (Primary backend constructor)
205     *
206     * \param interface_type Interface type
207     * \param parent_component Parent as passed to tInterface constructor (typically component)
208     * \param parent Parent framework element of primary backend
209     * \param primary_relation_id Relation ID to primary port type of root interface
210     * \param name Name of interface (must be unique in parent interfaces)
211     * \param convenience_port Whether port type below this backend is a convenience port type
212     * \param custom_connect_function Custom connect function for this interface
213     * \param create_missing_component_interface_function Function to create missing component interface
214     * \param primary_port_type Type of ports with relation id zero
215     * \param partial_interface Whether to instantiate a partial interface (this parameter is merged with scoped extra constructor parameters)
216     */
217    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);
218
219    /*!
220     * \return All backends that make up this port composite interface. The 'primary' backend is at index zero.
221     */
222    const std::vector<tBackend*>& AllBackends() const
223    {
224      return primary_backend.all_backends;
225    }
226
227    /*!
228     * Convenience method for connect functions (including custom ones)
229     * Connects all child ports of this and the provided backend that have the same name
230     *
231     * \param destination Second backend
232     * \param connect_options Any connect options to apply
233     */
234    void ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options = core::tConnectOptions());
235
236    /*!
237     * \param generic_port_backend Whether backend is a generic port (-> unspecified whether input or output)
238     * \return Default port flags for ports below this backend
239     */
240    core::tFrameworkElementFlags GetDefaultPortFlags(bool generic_port_backend) const;
241
242    /*!
243     * \return Whether this interface is a partial interface
244     */
245    bool IsPartialInterface() const
246    {
247      return partial_interface;
248    }
249
250    /*!
251     * \return Whether this is the primary backend
252     */
253    bool IsPrimaryBackend() const
254    {
255      return &primary_backend == this;
256    }
257
258    /*!
259     * \return Type of ports with relation id zero (as specified in constructor)
260     */
261    tPrimaryPortType PrimaryPortType() const
262    {
263      return primary_port_type;
264    }
265
266    //----------------------------------------------------------------------
267    // Protected methods
268    //----------------------------------------------------------------------
269  protected:
270
271    virtual void OnConnect(tAbstractPort& partner, bool partner_is_destination) override;
272
273    virtual void OnDisconnect(tAbstractPort& partner, bool partner_is_destination) override;
274
275    void OnInitialization() override;
276
277    void OnManagedDelete() override;
278
279    void SetFlag(tFlag flag, bool value = true)
280    {
281      core::tAbstractPort::SetFlag(flag, value);
282    }
283
284    //----------------------------------------------------------------------
285    // Private fields and methods
286    //----------------------------------------------------------------------
287  private:
288
289    friend class tInterfaceBase;
290    friend class internal::tInterfaceFactory;
291
292    template <int Tprimary_interface_relations, template <typename> class TPortType, typename T, bool Trpc, bool Tdirection_specified>
293    friend class internal::tGenericPortType;
294
295    template <template <typename> class TPort>
296    friend class tInterface;
297
298
299    /*! Parent as passed to tInterface constructor (typically component) */
300    core::tFrameworkElement* parent_component;
301
302    /*! Pointer to primary backend (for primary port type) */
303    tBackend& primary_backend;
304
305    /*!
306     * All backends that make up this port composite interface (first is relation id)
307     * The 'primary' backend is at index zero.
308     * It contains and manages the connections to other interfaces.
309     * This vector is only filled and maintained in the primary backend.
310     */
311    std::vector<tBackend*> all_backends;
312    std::vector<std::pair<int, tBackend*>> relation_backend_mapping;
313
314    /*! Custom connect function for this interface */
315    tConnectFunction custom_connect_function;
316
317    /*!
318     * Helper variable for e.g. initialization and deletion of all backends
319     * (only primary backend instance's version is valid)
320     */
321    bool operation_on_all_elements_pending = false;
322
323    /*! Whether port type below this backend is a convenience port type */
324    bool convenience_port_type;
325
326    /*! Relation ID to primary port type of root interface */
327    int primary_relation_id;
328
329    /*! Function to create missing component interface */
330    tCreateMissingComponentInterfaceFunction create_missing_component_interface_function;
331
332    /*! Type of ports with relation id zero */
333    tPrimaryPortType primary_port_type;
334
335    /*! Whether this interface is a partial interface */
336    bool partial_interface;
337
338    /*!
339     * Constructor for secondary instances
340     */
341    tBackend(core::tAbstractPortCreationInfo& creation_info, tBackend& primary);
342
343    /*!
344     * (called by tGenericPortType)
345     * \param primary_relation_id Relation id to primary port type
346     * \return Whether port with this relation is an output (or client) port
347     */
348    bool CreateOutputPort(int primary_relation_id);
349
350    /*!
351     * (called by tGenericPortType)
352     * \param primary_relation_id Relation id to primary port type
353     * \return Backend with specified index
354     */
355    tBackend* GetBackend(int primary_relation_id);
356  };
357
358//----------------------------------------------------------------------
359// Protected methods
360//----------------------------------------------------------------------
361protected:
362
363  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);
364  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);
365
366  /*!
367   * \return Parent as passed to tInterface constructor (typically component)
368   */
369  inline core::tFrameworkElement* ParentComponent() const
370  {
371    return Backend() ? Backend()->parent_component : nullptr;
372  }
373
374  template <typename TParent>
375  static constexpr tCreateMissingComponentInterfaceFunction GetDefaultCreateMissingInterfaceFunction()
376  {
377    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;
378    return &tHelper::template CreateMissingInterface<>;
379  }
380
381  /*! Additional constructor parameters that are not passed through tInterface constructor - for convenience and backward-compatibility */
382  struct tExtraConstructorParameters
383  {
384    bool partial_interface = false;
385  };
386
387  class tScopedExtraConstructorParameters
388  {
389  public:
390
391    tScopedExtraConstructorParameters() :
392      parameters(nullptr)
393    {}
394
395    tScopedExtraConstructorParameters(tScopedExtraConstructorParameters && other) :
396      parameters(nullptr)
397    {
398      this->lock = std::move(other.lock);
399      std::swap(parameters, other.parameters);
400    }
401
402    tScopedExtraConstructorParameters& operator=(tScopedExtraConstructorParameters && other)
403    {
404      this->lock = std::move(other.lock);
405      std::swap(parameters, other.parameters);
406      return *this;
407    }
408
409    inline tExtraConstructorParameters* operator->()
410    {
411      return parameters;
412    }
413
414    static tScopedExtraConstructorParameters Get();
415
416    ~tScopedExtraConstructorParameters()
417    {
418      if (parameters)
419      {
420        *parameters = tExtraConstructorParameters();
421      }
422    }
423
424  private:
425
426    tScopedExtraConstructorParameters(rrlib::thread::tRecursiveMutex& mutex, tExtraConstructorParameters* parameters) :
427      lock(mutex),
428      parameters(parameters)
429    {}
430
431    rrlib::thread::tLock lock;
432    tExtraConstructorParameters* parameters;
433  };
434
435//----------------------------------------------------------------------
436// Private fields and methods
437//----------------------------------------------------------------------
438private:
439
440  template <template <typename> class TPort>
441  friend class tInterface;
442  friend class internal::tInterfaceFactory;
443
444  /*! Helper class to extract type info on interfaces */
445  struct tInterfaceTypeData
446  {
447    rrlib::rtti::tType type;
448    tPrimaryPortType primary_port_type;
449  };
450
451  struct ForOtherComponents
452  {
453    template <typename TParent = core::tFrameworkElement>
454    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
455    {
456      return nullptr;
457    }
458  };
459
460  struct ForModules
461  {
462    template <typename TParent = structure::tModule>
463    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
464    {
465      TParent* module = static_cast<TParent*>(parent);
466      if ((TParent::cINPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
467      {
468        return &module->GetInputs();
469      }
470      else if ((TParent::cOUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
471      {
472        return &module->GetOutputs();
473      }
474      else if (required_flags.Get(tFlag::PARAMETER_INTERFACE))
475      {
476        return &module->GetParameters();
477      }
478      else if (required_flags.Get(tFlag::INTERFACE_FOR_RPC_PORTS))
479      {
480        return &module->GetServices();
481      }
482      return nullptr;
483    }
484  };
485
486  struct ForSenseControlModules
487  {
488    template <typename TParent = structure::tSenseControlModule>
489    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
490    {
491      TParent* module = static_cast<TParent*>(parent);
492      if ((TParent::cSENSOR_INPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
493      {
494        return &module->GetSensorInputs();
495      }
496      else if ((TParent::cSENSOR_OUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
497      {
498        return &module->GetSensorOutputs();
499      }
500      if ((TParent::cCONTROLLER_INPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
501      {
502        return &module->GetControllerInputs();
503      }
504      else if ((TParent::cCONTROLLER_OUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
505      {
506        return &module->GetControllerOutputs();
507      }
508      else if (required_flags.Get(tFlag::PARAMETER_INTERFACE))
509      {
510        return &module->GetParameters();
511      }
512      else if (required_flags.Get(tFlag::INTERFACE_FOR_RPC_PORTS))
513      {
514        return &module->GetServices();
515      }
516      return nullptr;
517    }
518  };
519};
520
521//----------------------------------------------------------------------
522// End of namespace declaration
523//----------------------------------------------------------------------
524}
525}
526
527#endif
Note: See TracBrowser for help on using the repository browser.