source: finroc_plugins_composite_ports/tInterfaceBase.cpp @ 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: 33.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.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2020-01-14
27 *
28 */
29//----------------------------------------------------------------------
30#include "plugins/composite_ports/tInterfaceBase.h"
31
32//----------------------------------------------------------------------
33// External includes (system with <>, local with "")
34//----------------------------------------------------------------------
35#include "core/tFrameworkElementTags.h"
36#include "core/tRuntimeEnvironment.h"
37#include "rrlib/util/string.h"
38#include "rrlib/rtti_conversion/tStaticCastOperation.h"
39
40//----------------------------------------------------------------------
41// Internal includes with ""
42//----------------------------------------------------------------------
43#include "plugins/composite_ports/internal/tInterfaceTypeInfo.h"
44#include "plugins/composite_ports/internal/type_traits.h"
45#include "plugins/composite_ports/tInterfaceModifier.h"
46
47//----------------------------------------------------------------------
48// Debugging
49//----------------------------------------------------------------------
50#include <cassert>
51
52//----------------------------------------------------------------------
53// Namespace usage
54//----------------------------------------------------------------------
55
56//----------------------------------------------------------------------
57// Namespace declaration
58//----------------------------------------------------------------------
59namespace finroc
60{
61namespace composite_ports
62{
63
64//----------------------------------------------------------------------
65// Forward declarations / typedefs / enums
66//----------------------------------------------------------------------
67typedef core::tFrameworkElementFlag tFlag;
68
69//----------------------------------------------------------------------
70// Const values
71//----------------------------------------------------------------------
72const std::string cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION = "finroc.composite_ports.single_backend_instantiation";
73
74//----------------------------------------------------------------------
75// Implementation
76//----------------------------------------------------------------------
77
78namespace
79{
80
81const tInterfaceModifier::tImplementation cMODIFIER_DEFAULT_IMPLEMENTATION;
82
83const core::tFrameworkElement* GetAggregator(const core::tFrameworkElement& element, core::tFrameworkElementFlags* extend_with_default_ports_flags = nullptr)
84{
85  if (element.GetFlag(tFlag::EDGE_AGGREGATOR) && (!element.IsPort()))
86  {
87    if (element.GetFlag(tFlag::INTERFACE) && extend_with_default_ports_flags)
88    {
89      (*extend_with_default_ports_flags) |= static_cast<const core::tPortGroup&>(element).GetDefaultPortFlags();
90      if (element.GetFlag(tFlag::SENSOR_DATA))
91      {
92        (*extend_with_default_ports_flags) |= tFlag::SENSOR_DATA;
93      }
94      if (element.GetFlag(tFlag::CONTROLLER_DATA))
95      {
96        (*extend_with_default_ports_flags) |= tFlag::CONTROLLER_DATA;
97      }
98      if (element.GetFlag(tFlag::INTERFACE_FOR_INPUTS) || element.GetFlag(tFlag::PARAMETER_INTERFACE))
99      {
100        (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_INPUT_PORT_FLAGS;
101      }
102      if (element.GetFlag(tFlag::INTERFACE_FOR_OUTPUTS))
103      {
104        (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_OUTPUT_PORT_FLAGS;
105      }
106      if (element.GetFlag(tFlag::PROXY_INTERFACE))
107      {
108        (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA;
109      }
110      if (element.GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
111      {
112        (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA;
113      }
114    }
115    return &element;
116  }
117  return element.GetParent() ? GetAggregator(*element.GetParent(), extend_with_default_ports_flags) : nullptr;
118}
119
120tInterfaceBase::tPrimaryPortType ModifierDefinesPartialInterface(const core::tFrameworkElement& parent_interface, const rrlib::rtti::tType& interface_type)
121{
122  if ((!parent_interface.IsPort()) && parent_interface.GetFlag(tFlag::INTERFACE) && internal::IsComponent(parent_interface.GetParent()))
123  {
124    tInterfaceModifier* interface_modifier = parent_interface.GetParent()->GetAnnotation<tInterfaceModifier>();
125    if (interface_modifier)
126    {
127      return interface_modifier->Implementation().PartialInterface(interface_type);
128    }
129  }
130  return tInterfaceBase::tPrimaryPortType::ANY;
131}
132
133tInterfaceBase::tPrimaryPortType ModifierDefinesPartialInterface(const core::tFrameworkElement* any_element, const rrlib::rtti::tType& interface_type)
134{
135  if (any_element)
136  {
137    auto aggregator = GetAggregator(*any_element);
138    return ModifierDefinesPartialInterface(*aggregator, interface_type);
139  }
140  return tInterfaceBase::tPrimaryPortType::ANY;
141}
142
143core::tAbstractPortCreationInfo MakeCreationInfo(const rrlib::rtti::tType& interface_type, const std::string& name, core::tFrameworkElement& parent_interface, bool partial_interface)
144{
145  core::tAbstractPortCreationInfo result;
146  result.data_type = interface_type;
147  if (partial_interface)
148  {
149    auto partial_type = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo()).GetPartialType();
150    result.data_type = partial_type ? partial_type : result.data_type;
151  }
152  result.parent = &parent_interface;
153  result.flags |= tFlag::INTERFACE;
154  GetAggregator(parent_interface, &result.flags);
155  result.name = name;
156  assert(result.flags.Get(tFlag::EMITS_DATA) || result.flags.Get(tFlag::ACCEPTS_DATA));
157  return result;
158}
159
160void FindInterfacesBelowImplementation(std::vector<tInterfaceBase>& result, core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces)
161{
162  for (auto it = parent.ChildrenBegin(); it != parent.ChildrenEnd(); ++it)
163  {
164    bool is_backend = typeid(*it) == typeid(tInterfaceBase::tBackend);
165    if (is_backend)
166    {
167      tInterfaceBase::tBackend& candidate = static_cast<tInterfaceBase::tBackend&>(*it);
168      if (candidate.IsPrimaryBackend() && (candidate.GetDataType() == type || ((!skip_derived_interfaces) && rrlib::rtti::conversion::tStaticCastOperation::IsImplicitlyConvertibleTo(candidate.GetDataType(), type))))
169      {
170        result.emplace_back(&candidate);
171        continue;
172      }
173    }
174    if ((!it->IsPort()) || is_backend)
175    {
176      FindInterfacesBelowImplementation(result, *it, type, skip_derived_interfaces);
177    }
178  }
179}
180
181}
182
183void tInterfaceBase::operator()(core::tAbstractPortCreationInfo& creation_info) const
184{
185  if ((!Backend()) || (Backend() && Backend()->convenience_port_type))
186  {
187    creation_info.flags |= tFlag::READY; // tComponent::cNO_PORT_NAME_BUILDER;
188  }
189  if (!Backend())
190  {
191    creation_info.flags |= tFlag::DELETED;
192    return;
193  }
194
195  creation_info.parent = &Backend()->primary_backend;
196
197  auto aggregator = GetAggregator(*creation_info.parent);
198  if (aggregator && aggregator->GetFlag(tFlag::INTERFACE))
199  {
200    creation_info.flags |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags();
201  }
202  const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw();
203  creation_info.flags |= core::tFrameworkElementFlags(creation_info.parent->GetAllFlags().Raw() & cRELEVANT_FLAGS);
204
205  if (Backend()->primary_backend.IsPartialInterface() && Backend()->primary_backend.PrimaryPortType() != tPrimaryPortType::ANY && Backend()->primary_backend.relation_backend_mapping.front().second == nullptr)
206  {
207    creation_info.flags |= tFlag::DELETED;
208  }
209
210  return;
211}
212
213core::tConnector* tInterfaceBase::ConnectTo(const tInterfaceBase& partner, const core::tConnectOptions& connect_options)
214{
215  if (Backend() && partner.Backend())
216  {
217    for (auto this_backend : Backend()->relation_backend_mapping)
218    {
219      for (auto other_backend : partner.Backend()->primary_backend.relation_backend_mapping)
220      {
221        if (this_backend.second && other_backend.second && this_backend.first - Backend()->primary_relation_id == other_backend.first - partner.Backend()->primary_relation_id)
222        {
223          return this_backend.second->ConnectTo(*other_backend.second, connect_options);
224        }
225      }
226    }
227  }
228  return nullptr;
229}
230
231tInterfaceBase::tBackend* tInterfaceBase::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)
232{
233  assert(parent);
234  if (parent->Backend() == nullptr)
235  {
236    return nullptr;
237  }
238  tBackend* parent_backend = parent->Backend()->GetBackend(primary_relation_id);
239  bool partial_interface = false;
240  assert(parent_backend || parent->Backend()->IsPartialInterface());
241  if (!parent_backend)
242  {
243    const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo());
244    interface_type = info.GetPartialType();
245    partial_interface = interface_type && primary_port_type != tPrimaryPortType::ANY;
246    if (partial_interface)
247    {
248      parent_backend = parent->Backend();
249    }
250  }
251  return parent_backend ? new tInterfaceBase::tBackend(interface_type, convience_port_type ? parent->ParentComponent() : parent->Backend(), parent_backend, primary_relation_id, name, convience_port_type, custom_connect_function, nullptr, parent->Backend()->PrimaryPortType(), partial_interface) : nullptr;
252}
253
254tInterfaceBase::tBackend* tInterfaceBase::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)
255{
256  const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo());
257  return parent ? new tInterfaceBase::tBackend(info.GetPartialType(), convience_port_type ? parent->parent_component : parent, parent, primary_relation_id, name, convience_port_type, custom_connect_function, nullptr, parent->PrimaryPortType(), true) : nullptr;
258}
259
260void tInterfaceBase::SetConfigEntry(const rrlib::uri::tPath& config_entry)
261{
262  uint interface_count = 0;
263  auto primary_backend = this->Backend();
264  if (primary_backend)
265  {
266    for (auto backend : primary_backend->primary_backend.all_backends)
267    {
268      auto aggregator = GetAggregator(*backend);
269      if (aggregator && (!aggregator->IsPort()) && aggregator->GetFlag(tFlag::INTERFACE) && aggregator->GetFlag(tFlag::PARAMETER_INTERFACE))
270      {
271        auto parameter_info = backend->GetAnnotation<parameters::internal::tParameterInfo>();
272        if (!parameter_info)
273        {
274          parameter_info = &backend->EmplaceAnnotation<parameters::internal::tParameterInfo>();
275        }
276        std::stringstream temp;  // Temporary solution until tParameterInfo class accepts paths
277        temp << config_entry;
278        parameter_info->SetConfigEntry(temp.str(), false);
279        interface_count++;
280      }
281    }
282    if (!interface_count)
283    {
284      FINROC_LOG_PRINT(WARNING, "No parameters backend in interface ", *primary_backend);
285    }
286  }
287  else
288  {
289    FINROC_LOG_PRINT(WARNING, "Called on empty interface wrapper");
290  }
291}
292
293
294tInterfaceBase::tBackend::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_type, const tConnectFunction& custom_connect_function, tCreateMissingComponentInterfaceFunction create_missing_component_interface_function, tPrimaryPortType primary_port_type, bool partial_interface) :
295  tAbstractPort(MakeCreationInfo(interface_type, name, *parent, partial_interface || tScopedExtraConstructorParameters::Get()->partial_interface || ModifierDefinesPartialInterface(parent, interface_type))),
296  parent_component(parent_component),
297  primary_backend(*this),
298  custom_connect_function(custom_connect_function),
299  convenience_port_type(convenience_port_type),
300  primary_relation_id(primary_relation_id),
301  create_missing_component_interface_function(create_missing_component_interface_function),
302  primary_port_type(primary_port_type),
303  partial_interface(static_cast<const internal::tInterfaceTypeInfo&>(GetDataType().SharedTypeInfo()).GetFullType() != GetDataType()),
304  partial_interface_primary_port_type(true)
305{
306  all_backends.emplace_back(this);
307  tBackend* primary_relation_backend = this;
308  if (this->partial_interface && primary_port_type != tPrimaryPortType::ANY)
309  {
310    auto aggregator = GetAggregator(*this);
311    auto partial_definition = ModifierDefinesPartialInterface(*aggregator, interface_type);
312    if (partial_definition != tPrimaryPortType::ANY)
313    {
314      this->partial_interface_primary_port_type = partial_definition == primary_port_type;
315    }
316    else
317    {
318      bool sensor_parent = (aggregator && (aggregator->GetFlag(tFlag::SENSOR_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::SENSOR_PORT));
319      bool controller_parent = (aggregator && (aggregator->GetFlag(tFlag::CONTROLLER_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::CONTROLLER_PORT));
320      if ((sensor_parent && primary_port_type == tPrimaryPortType::CONTROLLER_PORT) || (controller_parent && primary_port_type == tPrimaryPortType::SENSOR_PORT))
321      {
322        this->partial_interface_primary_port_type = false;
323      }
324    }
325    if (!this->partial_interface_primary_port_type)
326    {
327      primary_relation_backend = nullptr;
328    }
329  }
330  relation_backend_mapping.emplace_back(primary_relation_id, primary_relation_backend);
331}
332
333tInterfaceBase::tBackend::tBackend(core::tAbstractPortCreationInfo& creation_info, tBackend& primary) :
334  tAbstractPort(creation_info),
335  primary_backend(primary),
336  convenience_port_type(false),
337  primary_relation_id(primary.primary_relation_id),
338  create_missing_component_interface_function(nullptr),
339  primary_port_type(primary.primary_port_type),
340  partial_interface(primary.partial_interface),
341  partial_interface_primary_port_type(primary.partial_interface_primary_port_type)
342{
343}
344
345void tInterfaceBase::tBackend::ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options)
346{
347  for (auto port = this->ChildPortsBegin(); port != this->ChildPortsEnd(); ++port)
348  {
349    auto other_port = destination.GetChild(port->GetName());
350    if (other_port && other_port->IsPort())
351    {
352      if (port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE)
353      {
354        auto option_copy = connect_options;
355        option_copy.flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, false);
356        option_copy.flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, false);
357        port->ConnectTo(static_cast<core::tAbstractPort&>(*other_port), option_copy);
358      }
359      else
360      {
361        port->ConnectTo(static_cast<core::tAbstractPort&>(*other_port), connect_options);
362      }
363    }
364  }
365}
366
367bool tInterfaceBase::tBackend::CreateOutputPort(int primary_relation_id)
368{
369  auto backend = GetBackend(primary_relation_id);
370  if (!backend)
371  {
372    return false;
373  }
374  auto component_interface = GetAggregator(*backend);
375  if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
376  {
377    return false;
378  }
379  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
380  {
381    int last_relation = primary_relation_id & 0xFF;
382    bool derived_from_backend_is_output = CreateOutputPort(primary_relation_id >> 8);
383    if (last_relation == internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT)
384    {
385      return !derived_from_backend_is_output;
386    }
387    else if (last_relation == internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT)
388    {
389      return derived_from_backend_is_output;
390    }
391  }
392  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS))
393  {
394    return true;
395  }
396  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_INPUTS) || component_interface->GetFlag(tFlag::PARAMETER_INTERFACE))
397  {
398    return false;
399  }
400  throw std::runtime_error("Unspecified port direction");
401}
402
403core::tAbstractPort* tInterfaceBase::tBackend::CreatePort(const core::tAbstractPortCreationInfo& creation_info, int primary_relation_id) const
404{
405  return cMODIFIER_DEFAULT_IMPLEMENTATION.CreatePort(creation_info, primary_relation_id);
406}
407
408std::vector<tInterfaceBase> tInterfaceBase::FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces)
409{
410  std::vector<tInterfaceBase> result;
411  if (type.GetTypeClassification() == rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE)
412  {
413    FindInterfacesBelowImplementation(result, parent, type, skip_derived_interfaces);
414  }
415  return result;
416}
417
418tInterfaceBase::tBackend* tInterfaceBase::tBackend::GetBackend(int primary_relation_id)
419{
420  if (&primary_backend != this)
421  {
422    return primary_backend.GetBackend(primary_relation_id);
423  }
424
425  for (auto & entry : relation_backend_mapping)
426  {
427    if (entry.first == primary_relation_id)
428    {
429      return entry.second;
430    }
431  }
432
433  core::tFrameworkElement* parent = nullptr;
434  bool do_not_create_primary_port_type = relation_backend_mapping.front().second == nullptr;
435  bool partial_interface_direction_is_output = GetAggregator(*this)->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS);
436  bool partial_interface_primary_relation_direction_is_output = !partial_interface_direction_is_output;
437  if (GetParent() && typeid(*GetParent()).name() == typeid(tBackend).name())
438  {
439    parent = static_cast<tBackend&>(*GetParent()).GetBackend(primary_relation_id);
440  }
441  else if (core::tFrameworkElementTags::IsTagged(*this->GetParent(), cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION))
442  {
443    parent = this->GetParent();
444  }
445  else if (this->partial_interface && (!IsPartOfPartialInstantiation(primary_relation_id, this->partial_interface_primary_port_type)))
446  {
447    parent = nullptr; // Skip
448  }
449  else
450  {
451    // Actually process relation
452    std::vector<int> relation_list;
453    tFrameworkElement* component_interface = this->GetParent();
454    int relation_id = primary_relation_id;
455    if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
456    {
457      FINROC_LOG_PRINT(WARNING, "Generic creation of port composite interfaces with multiple port types only works on components");
458      throw std::runtime_error("Generic creation of port composite interfaces with multiple port types only works on components");
459    }
460
461    const core::tFrameworkElementFlags relevant_flags = tFlag::SENSOR_DATA | tFlag::CONTROLLER_DATA | tFlag::INTERFACE_FOR_INPUTS | tFlag::INTERFACE_FOR_OUTPUTS | tFlag::PROXY_INTERFACE | tFlag::PARAMETER_INTERFACE;
462    tInterfaceModifier* interface_modifier = component_interface->GetParent()->GetAnnotation<tInterfaceModifier>();
463
464    // Compute opcode sequence
465    {
466      while (relation_id)
467      {
468        int opcode = relation_id & 0xFF;
469        relation_list.push_back(opcode);
470        relation_id = relation_id >> 8;
471      }
472      std::reverse(relation_list.begin(), relation_list.end());
473    }
474
475    tFrameworkElement* parent_candidate = do_not_create_primary_port_type ? nullptr : component_interface;
476    core::tFrameworkElementFlags use_these_original_flags;
477    if (do_not_create_primary_port_type)
478    {
479      assert(partial_interface && primary_port_type != tPrimaryPortType::ANY);
480      use_these_original_flags = tFlag::INTERFACE_FOR_DATA_PORTS | (primary_port_type == tPrimaryPortType::SENSOR_PORT ? tFlag::SENSOR_DATA : tFlag::CONTROLLER_DATA) | (partial_interface_primary_relation_direction_is_output ? tFlag::INTERFACE_FOR_OUTPUTS : tFlag::INTERFACE_FOR_INPUTS);
481      use_these_original_flags.Set(tFlag::PROXY_INTERFACE, component_interface->GetFlag(tFlag::PROXY_INTERFACE));
482    }
483
484    int remaining_relations = relation_list.size();
485    for (int opcode : relation_list)
486    {
487      remaining_relations--;
488      core::tFrameworkElementFlags original_flags = use_these_original_flags.Raw() ? use_these_original_flags : parent_candidate->GetAllFlags();
489      use_these_original_flags = core::tFrameworkElementFlags();
490      core::tFrameworkElementFlags target_set_flags = core::tFrameworkElementFlags(original_flags.Raw() & relevant_flags.Raw());
491      core::tFrameworkElementFlags target_unset_flags = core::tFrameworkElementFlags((~original_flags.Raw()) & relevant_flags.Raw());
492
493      typedef internal::tPortTypeRelation tOpCode;
494      switch (opcode)
495      {
496      case tOpCode::ePTR_COUNTER_PART:
497      case tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT:
498        if (original_flags.Get(tFlag::CONTROLLER_DATA) && (!original_flags.Get(tFlag::SENSOR_DATA)))
499        {
500          target_set_flags.Set(tFlag::SENSOR_DATA);
501          target_set_flags.Set(tFlag::CONTROLLER_DATA, false);
502          target_unset_flags.Set(tFlag::CONTROLLER_DATA);
503          target_unset_flags.Set(tFlag::SENSOR_DATA, false);
504        }
505        if (original_flags.Get(tFlag::SENSOR_DATA) && (!original_flags.Get(tFlag::CONTROLLER_DATA)))
506        {
507          target_set_flags.Set(tFlag::CONTROLLER_DATA);
508          target_set_flags.Set(tFlag::SENSOR_DATA, false);
509          target_unset_flags.Set(tFlag::SENSOR_DATA);
510          target_unset_flags.Set(tFlag::CONTROLLER_DATA, false);
511        }
512        if (original_flags.Get(tFlag::INTERFACE_FOR_INPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS)))
513        {
514          target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
515          target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
516          target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
517          target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
518          target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
519        }
520        if (original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_INPUTS)))
521        {
522          if (opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT)
523          {
524            target_set_flags = tFlag::PARAMETER_INTERFACE;
525            target_unset_flags = core::tFrameworkElementFlags();
526          }
527          else
528          {
529            target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
530            target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
531            target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
532            target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
533          }
534        }
535        break;
536      case internal::tPortTypeRelation::ePTR_INPUT:
537        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
538        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
539        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
540        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
541        break;
542      case internal::tPortTypeRelation::ePTR_OUTPUT:
543        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
544        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
545        target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
546        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
547        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
548        break;
549      case internal::tPortTypeRelation::ePTR_PARAMETER:
550        target_set_flags = tFlag::PARAMETER_INTERFACE;
551        target_unset_flags = core::tFrameworkElementFlags();
552        break;
553      case internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT:
554      case internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT:
555        target_set_flags = tFlag::INTERFACE_FOR_RPC_PORTS;
556        target_unset_flags = (partial_interface && (!parent_candidate)) ? target_set_flags : core::tFrameworkElementFlags(); // With partially instantiated interfaces, create service ports if the port types they are derived from are also created
557        break;
558      default:
559        break;
560      }
561
562      core::tFrameworkElement* new_candidate = nullptr;
563      size_t candidate_name_length_difference = std::numeric_limits<size_t>::max();
564      auto component = component_interface->GetParent();
565      for (auto it = component->ChildrenBegin(); it != component->ChildrenEnd(); ++it)
566      {
567        if ((!it->IsPort()) && it->GetFlag(tFlag::INTERFACE) && (it->GetAllFlags().Raw() & target_set_flags.Raw()) == target_set_flags.Raw() && (it->GetAllFlags().Raw() & target_unset_flags.Raw()) == 0)
568        {
569          size_t name_length_difference = std::abs(static_cast<long>(component_interface->GetName().length()) - static_cast<long>(it->GetName().length()));
570          if (name_length_difference < candidate_name_length_difference)
571          {
572            new_candidate = &*it;
573            candidate_name_length_difference = name_length_difference;
574          }
575        }
576      }
577
578      if ((!new_candidate) && ((this->IsPartialInterface() && remaining_relations) || interface_modifier))
579      {
580        use_these_original_flags = target_set_flags;
581        parent_candidate = nullptr;
582        continue;
583      }
584
585      // Not-yet-created component interfaces - until there is a generic way to do this
586      if ((!new_candidate) && create_missing_component_interface_function)
587      {
588        new_candidate = (*create_missing_component_interface_function)(component_interface->GetParent(), target_set_flags);
589      }
590
591      if (new_candidate)
592      {
593        component_interface = new_candidate;
594        parent_candidate = new_candidate;
595      }
596      else
597      {
598        std::stringstream message;
599        message << "Generic creation of port composite interface failed: No interface with relation " << make_builder::GetEnumString(static_cast<tOpCode>(opcode)) << " found below " << *component_interface->GetParent();
600        FINROC_LOG_PRINT(WARNING, message.str());
601        throw std::runtime_error(message.str());
602      }
603    }
604    assert(remaining_relations == 0);
605
606    parent = parent_candidate;
607    if (interface_modifier)
608    {
609      parent = interface_modifier->Implementation().GetComponentInterface(parent_candidate && parent_candidate->GetFlag(tFlag::INTERFACE) ? static_cast<core::tPortGroup*>(parent_candidate) : nullptr, primary_relation_id);
610    }
611  }
612
613  if (!parent)
614  {
615    relation_backend_mapping.emplace_back(primary_relation_id, nullptr);
616    return nullptr;
617  }
618
619  for (auto backend : all_backends)
620  {
621    if (backend->GetParent() == parent)
622    {
623      relation_backend_mapping.emplace_back(primary_relation_id, backend);
624      return backend;
625    }
626  }
627
628  // Create new backend below this parent
629  assert(parent != this->GetParent());
630  core::tAbstractPortCreationInfo secondary_creation_info;
631  secondary_creation_info.data_type = this->GetDataType();
632  secondary_creation_info.name = GetName();
633  secondary_creation_info.parent = parent;
634  secondary_creation_info.flags = core::tFrameworkElementFlags(tFlag::INTERFACE);
635  GetAggregator(*parent, &secondary_creation_info.flags);
636  all_backends.push_back(new tBackend(secondary_creation_info, *this));
637  relation_backend_mapping.emplace_back(primary_relation_id, all_backends.back());
638  return all_backends.back();
639}
640
641core::tFrameworkElementFlags tInterfaceBase::tBackend::GetDefaultPortFlags(bool generic_port_backend) const
642{
643  core::tFrameworkElementFlags result;
644  if (generic_port_backend)
645  {
646    GetAggregator(*this, &result);
647  }
648  else
649  {
650    auto aggregator = GetAggregator(*this);
651    if (aggregator && aggregator->GetFlag(tFlag::INTERFACE))
652    {
653      if (aggregator->GetFlag(tFlag::PROXY_INTERFACE))
654      {
655        result |= (tFlag::ACCEPTS_DATA | tFlag::EMITS_DATA | tFlag::PUSH_STRATEGY);
656      }
657      result |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags();
658    }
659    const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw();
660    result |= core::tFrameworkElementFlags(this->GetAllFlags().Raw() & cRELEVANT_FLAGS);
661  }
662  return result;
663}
664
665bool tInterfaceBase::tBackend::IsPartOfPartialInstantiation(int primary_relation_id, bool partial_instantiation_variant_primary_port_type)
666{
667  typedef internal::tPortTypeRelation tOpCode;
668  int switch_count = 0;
669  while (primary_relation_id)
670  {
671    int opcode = primary_relation_id & 0xFF;
672    switch_count += ((opcode == tOpCode::ePTR_COUNTER_PART || opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT) ? 1 : 0);
673    primary_relation_id = primary_relation_id >> 8;
674  }
675  bool primary_port_type_relation_id = (switch_count % 2) == 0;
676  return primary_port_type_relation_id == partial_instantiation_variant_primary_port_type;
677}
678
679void tInterfaceBase::tBackend::OnConnect(tAbstractPort& partner, bool partner_is_destination)
680{
681  if (primary_backend.operation_on_all_elements_pending)
682  {
683    return;
684  }
685
686  tBackend& other = static_cast<tBackend&>(partner);
687  bool connect_all_backends = this->IsPrimaryBackend() && other.IsPrimaryBackend();
688
689  primary_backend.operation_on_all_elements_pending = true;
690  try
691  {
692    if (primary_backend.custom_connect_function)
693    {
694      if (partner_is_destination)
695      {
696        primary_backend.custom_connect_function(*this, other);
697      }
698      else
699      {
700        primary_backend.custom_connect_function(other, *this);
701      }
702      primary_backend.operation_on_all_elements_pending = false;
703      return;
704    }
705
706    // Connect all matching backends and ports
707    for (auto this_backend : primary_backend.relation_backend_mapping)
708    {
709      for (auto other_backend : other.primary_backend.primary_backend.relation_backend_mapping)
710      {
711        if (this_backend.second && other_backend.second && this_backend.first - primary_backend.primary_relation_id == other_backend.first - other.primary_backend.primary_relation_id && (connect_all_backends || this_backend.second == this || other_backend.second == &other))
712        {
713          core::tConnectionFlag direction = (this->IsOutputPort() == this_backend.second->IsOutputPort() ? partner_is_destination : (!partner_is_destination)) ? core::tConnectionFlag::DIRECTION_TO_DESTINATION : core::tConnectionFlag::DIRECTION_TO_SOURCE;
714          this_backend.second->ConnectTo(*other_backend.second, direction);
715          this_backend.second->ConnectChildPortsByName(*other_backend.second, direction);
716        }
717      }
718    }
719  }
720  catch (const std::exception& e)
721  {
722    FINROC_LOG_PRINT(WARNING, "Connecting failed: ", e);
723  }
724  primary_backend.operation_on_all_elements_pending = false;
725}
726
727void tInterfaceBase::tBackend::OnDisconnect(tAbstractPort& partner, bool partner_is_destination)
728{
729  bool& pending = primary_backend.primary_backend.operation_on_all_elements_pending;
730  tBackend& other = static_cast<tBackend&>(partner).primary_backend;
731  if (pending || other.operation_on_all_elements_pending || partner_is_destination)
732  {
733    return;
734  }
735
736  pending = true;
737  try
738  {
739    // Update other backend connection info
740    for (auto this_backend : this->primary_backend.all_backends)
741    {
742      for (auto other_backend : other.primary_backend.all_backends)
743      {
744        this_backend->DisconnectFrom(*other_backend);
745      }
746    }
747
748    // Disconnect all ports to partner backends (this should also cover cases with custom connect function)
749    for (auto backend : primary_backend.all_backends)
750    {
751      for (auto port = backend->ChildPortsBegin(); port != backend->ChildPortsEnd(); ++port)
752      {
753        for (auto partner = port->IncomingConnectionsBegin(); partner != port->IncomingConnectionsEnd(); ++partner)
754        {
755          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Source().GetParent()))
756          {
757            port->DisconnectFrom(partner->Source());
758          }
759        }
760        for (auto partner = port->OutgoingConnectionsBegin(); partner != port->OutgoingConnectionsEnd(); ++partner)
761        {
762          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Destination().GetParent()))
763          {
764            port->DisconnectFrom(partner->Destination());
765          }
766        }
767      }
768    }
769  }
770  catch (const std::exception& e)
771  {
772    FINROC_LOG_PRINT(WARNING, "Disconnecting failed: ", e);
773  }
774  pending = false;
775}
776
777void tInterfaceBase::tBackend::OnInitialization()
778{
779  bool& pending = primary_backend.operation_on_all_elements_pending;
780  if (!pending)
781  {
782    pending = true;
783    for (auto backend : primary_backend.all_backends)
784    {
785      if (backend != this)
786      {
787        backend->Init();
788      }
789    }
790    pending = false;
791  }
792}
793
794void tInterfaceBase::tBackend::OnManagedDelete()
795{
796  rrlib::thread::tLock lock1(GetStructureMutex());
797
798  if (!core::tRuntimeEnvironment::ShuttingDown())
799  {
800    bool& pending = primary_backend.operation_on_all_elements_pending;
801    if (!pending)
802    {
803      pending = true;
804      for (auto backend : primary_backend.all_backends)
805      {
806        if (backend != this)
807        {
808          backend->ManagedDelete();
809        }
810      }
811      pending = false;
812    }
813  }
814
815  tAbstractPort::OnManagedDelete();
816}
817
818tInterfaceBase::tScopedExtraConstructorParameters tInterfaceBase::tScopedExtraConstructorParameters::Get()
819{
820  static tExtraConstructorParameters parameters;
821  return tScopedExtraConstructorParameters(core::tRuntimeEnvironment::GetInstance().GetStructureMutex(), &parameters);  //
822}
823
824
825//----------------------------------------------------------------------
826// End of namespace declaration
827//----------------------------------------------------------------------
828}
829}
Note: See TracBrowser for help on using the repository browser.