source: finroc_plugins_composite_ports/tInterfaceBase.cpp

tip
Last change on this file was 26:f783224f355c, checked in by Max Reichardt <mreichardt@…>, 7 months ago

Optimizes skill modifier integration (in particular, modifiers may now be attached to any node in the framework element tree)

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