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