source: finroc_plugins_composite_ports/tInterfaceBase.h @ 13:dbd30988fdb1

Last change on this file since 13:dbd30988fdb1 was 13:dbd30988fdb1, checked in by Max Reichardt <max.reichardt@…>, 3 years ago

Adds convenience method tInterfaceBase::FindInterfacesBelow

File size: 14.0 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  class tBackend;
103  typedef std::function<std::string(tBackend&, tBackend&)> tConnectFunction;  //!< First backend is data source primary backend, second backend is data destination primary backend
104  typedef core::tPortGroup* (*tCreateMissingComponentInterfaceFunction)(core::tFrameworkElement* parent, const core::tFrameworkElementFlags&);  //!< Flags are required flags of missing required interface
105
106  tInterfaceBase(tBackend* backend = nullptr) :
107    tPortWrapperBase(backend)
108  {}
109
110
111  void operator()(core::tAbstractPortCreationInfo& creation_info) const;
112
113  /*!
114   * \return Wrapped backend
115   */
116  tBackend* Backend()
117  {
118    return static_cast<tBackend*>(this->GetWrapped());
119  }
120  const tBackend* Backend() const
121  {
122    return static_cast<tBackend*>(this->GetWrapped());
123  }
124
125  /*!
126   * Searches for interfaces of specified type below parent element.
127   *
128   * \param parent Parent element below which to search for interface
129   * \param type Type of interface to search for
130   * \param skip_derived_interfaces By default subclasses of interfaces are also included. They are skipped if this parameter is true.
131   * \return Any interfaces found. Returns empty vector if type is not an interface type.
132   */
133  static std::vector<tInterfaceBase> FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces = false);
134
135  /*!
136   * \return Returns interface id for interface type TInterface
137   */
138  template <typename TInterface>
139  static rrlib::rtti::tType GetType()
140  {
141    tInterfaceTypeData result;
142    TInterface temp_instance("", &result);
143    return result.type;
144  }
145
146  /*!
147   * \param element Element to check
148   * \return Whether provided framework element is a port composite interface
149   */
150  static inline bool IsInterface(core::tFrameworkElement& element)
151  {
152    enum { cRELEVANT_FLAGS = (core::tFrameworkElementFlag::PORT | core::tFrameworkElementFlag::COMPOSITE_PORT).Raw() };
153    return (element.GetAllFlags().Raw() & cRELEVANT_FLAGS) == cRELEVANT_FLAGS;
154  }
155
156  class tBackend : public core::tAbstractPort
157  {
158    //----------------------------------------------------------------------
159    // Public methods
160    //----------------------------------------------------------------------
161  public:
162
163    /*!
164     * (Primary backend constructor)
165     *
166     * \param interface_type Interface type
167     * \param parent_component Parent as passed to tInterface constructor (typically component)
168     * \param parent Parent framework element of primary backend
169     * \param primary_relation_id Relation ID to primary port type of root interface
170     * \param name Name of interface (must be unique in parent interfaces)
171     * \param convenience_port Whether port type below this backend is a convenience port type
172     * \param custom_connect_function Custom connect function for this interface
173     * \param create_missing_component_interface_function Function to create missing component interface
174     */
175    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);
176
177    /*!
178     * \return All backends that make up this port composite interface. The 'primary' backend is at index zero.
179     */
180    const std::vector<tBackend*>& AllBackends() const
181    {
182      return primary_backend.all_backends;
183    }
184
185    /*!
186     * Convenience method for connect functions (including custom ones)
187     * Connects all child ports of this and the provided backend that have the same name
188     *
189     * \param destination Second backend
190     * \param connect_options Any connect options to apply
191     */
192    void ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options = core::tConnectOptions());
193
194    /*!
195     * \param any_port_type Whether backend is a generic port (-> unspecified whether input or output)
196     * \return Default port flags for ports below this backend
197     */
198    core::tFrameworkElementFlags GetDefaultPortFlags(bool generic_port_backend) const;
199
200    /*!
201     * \return Whether this is the primary backend
202     */
203    bool IsPrimaryBackend() const
204    {
205      return &primary_backend == this;
206    }
207
208    //----------------------------------------------------------------------
209    // Protected methods
210    //----------------------------------------------------------------------
211  protected:
212
213    virtual void OnConnect(tAbstractPort& partner, bool partner_is_destination) override;
214
215    virtual void OnDisconnect(tAbstractPort& partner, bool partner_is_destination) override;
216
217    void OnInitialization() override;
218
219    void OnManagedDelete() override;
220
221    void SetFlag(tFlag flag, bool value = true)
222    {
223      core::tAbstractPort::SetFlag(flag, value);
224    }
225
226    //----------------------------------------------------------------------
227    // Private fields and methods
228    //----------------------------------------------------------------------
229  private:
230
231    friend class tInterfaceBase;
232    friend class internal::tInterfaceFactory;
233
234    template <int Tprimary_interface_relations, template <typename> class TPortType, typename T, bool Trpc, bool Tdirection_specified>
235    friend class internal::tGenericPortType;
236
237    template <template <typename> class TPort>
238    friend class tInterface;
239
240
241    /*! Parent as passed to tInterface constructor (typically component) */
242    core::tFrameworkElement* parent_component;
243
244    /*! Pointer to primary backend (for primary port type) */
245    tBackend& primary_backend;
246
247    /*!
248     * All backends that make up this port composite interface (first is relation id)
249     * The 'primary' backend is at index zero.
250     * It contains and manages the connections to other interfaces.
251     * This vector is only filled and maintained in the primary backend.
252     */
253    std::vector<tBackend*> all_backends;
254    std::vector<std::pair<int, tBackend*>> relation_backend_mapping;
255
256    /*! Custom connect function for this interface */
257    tConnectFunction custom_connect_function;
258
259    /*!
260     * Helper variable for e.g. initialization and deletion of all backends
261     * (only primary backend instance's version is valid)
262     */
263    bool operation_on_all_elements_pending = false;
264
265    /*! Whether port type below this backend is a convenience port type */
266    bool convenience_port_type;
267
268    /*! Relation ID to primary port type of root interface */
269    int primary_relation_id;
270
271    /*! Function to create missing component interface */
272    tCreateMissingComponentInterfaceFunction create_missing_component_interface_function;
273
274    /*!
275     * Constructor for secondary instances
276     */
277    tBackend(core::tAbstractPortCreationInfo& creation_info, tBackend& primary);
278
279    /*!
280     * (called by tGenericPortType)
281     * \param primary_relation_id Relation id to primary port type
282     * \return Backend with specified index
283     */
284    tBackend* GetBackend(int primary_relation_id);
285  };
286
287//----------------------------------------------------------------------
288// Protected methods
289//----------------------------------------------------------------------
290protected:
291
292  /*!
293   * \return Parent as passed to tInterface constructor (typically component)
294   */
295  inline core::tFrameworkElement* ParentComponent() const
296  {
297    return Backend() ? Backend()->parent_component : nullptr;
298  }
299
300  template <typename TParent>
301  static constexpr tCreateMissingComponentInterfaceFunction GetDefaultCreateMissingInterfaceFunction()
302  {
303    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;
304    return &tHelper::template CreateMissingInterface<>;
305  }
306
307//----------------------------------------------------------------------
308// Private fields and methods
309//----------------------------------------------------------------------
310private:
311
312  template <template <typename> class TPort>
313  friend class tInterface;
314
315  /*! Helper class to extract type info about on interfaces */
316  struct tInterfaceTypeData
317  {
318    rrlib::rtti::tType type;
319  };
320
321  struct ForOtherComponents
322  {
323    template <typename TParent = core::tFrameworkElement>
324    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
325    {
326      return nullptr;
327    }
328  };
329
330  struct ForModules
331  {
332    template <typename TParent = structure::tModule>
333    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
334    {
335      TParent* module = static_cast<TParent*>(parent);
336      if ((TParent::cINPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
337      {
338        return &module->GetInputs();
339      }
340      else if ((TParent::cOUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
341      {
342        return &module->GetOutputs();
343      }
344      else if (required_flags.Get(tFlag::PARAMETER_INTERFACE))
345      {
346        return &module->GetParameters();
347      }
348      return nullptr;
349    }
350  };
351
352  struct ForSenseControlModules
353  {
354    template <typename TParent = structure::tSenseControlModule>
355    static core::tPortGroup* CreateMissingInterface(core::tFrameworkElement* parent, const core::tFrameworkElementFlags& required_flags)
356    {
357      TParent* module = static_cast<TParent*>(parent);
358      if ((TParent::cSENSOR_INPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
359      {
360        return &module->GetSensorInputs();
361      }
362      else if ((TParent::cSENSOR_OUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
363      {
364        return &module->GetSensorOutputs();
365      }
366      if ((TParent::cCONTROLLER_INPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
367      {
368        return &module->GetControllerInputs();
369      }
370      else if ((TParent::cCONTROLLER_OUTPUT_INTERFACE_INFO.interface_flags.Raw() & required_flags.Raw()) == required_flags.Raw())
371      {
372        return &module->GetControllerOutputs();
373      }
374      else if (required_flags.Get(tFlag::PARAMETER_INTERFACE))
375      {
376        return &module->GetParameters();
377      }
378      return nullptr;
379    }
380  };
381};
382
383//----------------------------------------------------------------------
384// End of namespace declaration
385//----------------------------------------------------------------------
386}
387}
388
389#endif
Note: See TracBrowser for help on using the repository browser.