source: finroc_plugins_composite_ports/tInterfaceBase.cpp @ 24:dff0cf79bc31

Last change on this file since 24:dff0cf79bc31 was 24:dff0cf79bc31, checked in by Max Reichardt <mreichardt@…>, 9 months ago

Fixes warning when modifiers move RPC ports

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
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  parent_component(primary.parent_component),
336  primary_backend(primary),
337  custom_connect_function(primary.custom_connect_function),
338  convenience_port_type(false),
339  primary_relation_id(primary.primary_relation_id),
340  create_missing_component_interface_function(nullptr),
341  primary_port_type(primary.primary_port_type),
342  partial_interface(primary.partial_interface),
343  partial_interface_primary_port_type(primary.partial_interface_primary_port_type)
344{
345}
346
347void tInterfaceBase::tBackend::ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options)
348{
349  for (auto port = this->ChildPortsBegin(); port != this->ChildPortsEnd(); ++port)
350  {
351    auto other_port = destination.GetChild(port->GetName());
352    if (other_port && other_port->IsPort())
353    {
354      if (port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE)
355      {
356        auto option_copy = connect_options;
357        option_copy.flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, false);
358        option_copy.flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, false);
359        port->ConnectTo(static_cast<core::tAbstractPort&>(*other_port), option_copy);
360      }
361      else
362      {
363        port->ConnectTo(static_cast<core::tAbstractPort&>(*other_port), connect_options);
364      }
365    }
366  }
367}
368
369bool tInterfaceBase::tBackend::CreateOutputPort(int primary_relation_id)
370{
371  auto backend = GetBackend(primary_relation_id);
372  if (!backend)
373  {
374    return false;
375  }
376  auto component_interface = GetAggregator(*backend);
377  if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
378  {
379    return false;
380  }
381  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
382  {
383    int last_relation = primary_relation_id & 0xFF;
384    bool derived_from_backend_is_output = CreateOutputPort(primary_relation_id >> 8);
385    if (last_relation == internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT)
386    {
387      return !derived_from_backend_is_output;
388    }
389    else if (last_relation == internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT)
390    {
391      return derived_from_backend_is_output;
392    }
393  }
394  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS))
395  {
396    return true;
397  }
398  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_INPUTS) || component_interface->GetFlag(tFlag::PARAMETER_INTERFACE))
399  {
400    return false;
401  }
402  throw std::runtime_error("Unspecified port direction");
403}
404
405core::tAbstractPort* tInterfaceBase::tBackend::CreatePort(const core::tAbstractPortCreationInfo& creation_info, int primary_relation_id) const
406{
407  return cMODIFIER_DEFAULT_IMPLEMENTATION.CreatePort(creation_info, primary_relation_id);
408}
409
410std::vector<tInterfaceBase> tInterfaceBase::FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces)
411{
412  std::vector<tInterfaceBase> result;
413  if (type.GetTypeClassification() == rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE)
414  {
415    FindInterfacesBelowImplementation(result, parent, type, skip_derived_interfaces);
416  }
417  return result;
418}
419
420tInterfaceBase::tBackend* tInterfaceBase::tBackend::GetBackend(int primary_relation_id)
421{
422  if (&primary_backend != this)
423  {
424    return primary_backend.GetBackend(primary_relation_id);
425  }
426
427  for (auto & entry : relation_backend_mapping)
428  {
429    if (entry.first == primary_relation_id)
430    {
431      return entry.second;
432    }
433  }
434
435  core::tFrameworkElement* parent = nullptr;
436  bool do_not_create_primary_port_type = relation_backend_mapping.front().second == nullptr;
437  bool partial_interface_direction_is_output = GetAggregator(*this)->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS);
438  bool partial_interface_primary_relation_direction_is_output = !partial_interface_direction_is_output;
439  bool backend_for_client_port = false;
440  if (GetParent() && typeid(*GetParent()).name() == typeid(tBackend).name())
441  {
442    parent = static_cast<tBackend&>(*GetParent()).GetBackend(primary_relation_id);
443  }
444  else if (core::tFrameworkElementTags::IsTagged(*this->GetParent(), cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION))
445  {
446    parent = this->GetParent();
447  }
448  else if (this->partial_interface && (!IsPartOfPartialInstantiation(primary_relation_id, this->partial_interface_primary_port_type)))
449  {
450    parent = nullptr; // Skip
451  }
452  else
453  {
454    // Actually process relation
455    std::vector<int> relation_list;
456    tFrameworkElement* component_interface = this->GetParent();
457    int relation_id = primary_relation_id;
458    if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
459    {
460      FINROC_LOG_PRINT(WARNING, "Generic creation of port composite interfaces with multiple port types only works on components");
461      throw std::runtime_error("Generic creation of port composite interfaces with multiple port types only works on components");
462    }
463
464    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;
465    tInterfaceModifier* interface_modifier = component_interface->GetParent()->GetAnnotation<tInterfaceModifier>();
466
467    // Compute opcode sequence
468    {
469      while (relation_id)
470      {
471        int opcode = relation_id & 0xFF;
472        relation_list.push_back(opcode);
473        relation_id = relation_id >> 8;
474      }
475      std::reverse(relation_list.begin(), relation_list.end());
476    }
477
478    tFrameworkElement* parent_candidate = do_not_create_primary_port_type ? nullptr : component_interface;
479    core::tFrameworkElementFlags use_these_original_flags;
480    if (do_not_create_primary_port_type)
481    {
482      assert(partial_interface && primary_port_type != tPrimaryPortType::ANY);
483      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);
484      use_these_original_flags.Set(tFlag::PROXY_INTERFACE, component_interface->GetFlag(tFlag::PROXY_INTERFACE));
485    }
486
487    int remaining_relations = relation_list.size();
488    for (int opcode : relation_list)
489    {
490      remaining_relations--;
491      core::tFrameworkElementFlags original_flags = use_these_original_flags.Raw() ? use_these_original_flags : parent_candidate->GetAllFlags();
492      use_these_original_flags = core::tFrameworkElementFlags();
493      core::tFrameworkElementFlags target_set_flags = core::tFrameworkElementFlags(original_flags.Raw() & relevant_flags.Raw());
494      core::tFrameworkElementFlags target_unset_flags = core::tFrameworkElementFlags((~original_flags.Raw()) & relevant_flags.Raw());
495
496      typedef internal::tPortTypeRelation tOpCode;
497      switch (opcode)
498      {
499      case tOpCode::ePTR_COUNTER_PART:
500      case tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT:
501        if (original_flags.Get(tFlag::CONTROLLER_DATA) && (!original_flags.Get(tFlag::SENSOR_DATA)))
502        {
503          target_set_flags.Set(tFlag::SENSOR_DATA);
504          target_set_flags.Set(tFlag::CONTROLLER_DATA, false);
505          target_unset_flags.Set(tFlag::CONTROLLER_DATA);
506          target_unset_flags.Set(tFlag::SENSOR_DATA, false);
507        }
508        if (original_flags.Get(tFlag::SENSOR_DATA) && (!original_flags.Get(tFlag::CONTROLLER_DATA)))
509        {
510          target_set_flags.Set(tFlag::CONTROLLER_DATA);
511          target_set_flags.Set(tFlag::SENSOR_DATA, false);
512          target_unset_flags.Set(tFlag::SENSOR_DATA);
513          target_unset_flags.Set(tFlag::CONTROLLER_DATA, false);
514        }
515        if (original_flags.Get(tFlag::INTERFACE_FOR_INPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS)))
516        {
517          target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
518          target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
519          target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
520          target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
521          target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
522        }
523        if (original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_INPUTS)))
524        {
525          if (opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT)
526          {
527            target_set_flags = tFlag::PARAMETER_INTERFACE;
528            target_unset_flags = core::tFrameworkElementFlags();
529          }
530          else
531          {
532            target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
533            target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
534            target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
535            target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
536          }
537        }
538        break;
539      case internal::tPortTypeRelation::ePTR_INPUT:
540        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
541        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
542        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
543        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
544        break;
545      case internal::tPortTypeRelation::ePTR_OUTPUT:
546        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
547        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
548        target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
549        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
550        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
551        break;
552      case internal::tPortTypeRelation::ePTR_PARAMETER:
553        target_set_flags = tFlag::PARAMETER_INTERFACE;
554        target_unset_flags = core::tFrameworkElementFlags();
555        break;
556      case internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT:
557      case internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT:
558        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)));
559        target_set_flags = tFlag::INTERFACE_FOR_RPC_PORTS;
560        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
561        break;
562      default:
563        break;
564      }
565
566      core::tFrameworkElement* new_candidate = nullptr;
567      size_t candidate_name_length_difference = std::numeric_limits<size_t>::max();
568      auto component = component_interface->GetParent();
569      for (auto it = component->ChildrenBegin(); it != component->ChildrenEnd(); ++it)
570      {
571        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)
572        {
573          size_t name_length_difference = std::abs(static_cast<long>(component_interface->GetName().length()) - static_cast<long>(it->GetName().length()));
574          if (name_length_difference < candidate_name_length_difference)
575          {
576            new_candidate = &*it;
577            candidate_name_length_difference = name_length_difference;
578          }
579        }
580      }
581
582      if ((!new_candidate) && ((this->IsPartialInterface() && remaining_relations) || interface_modifier))
583      {
584        use_these_original_flags = target_set_flags;
585        parent_candidate = nullptr;
586        continue;
587      }
588
589      // Not-yet-created component interfaces - until there is a generic way to do this
590      if ((!new_candidate) && create_missing_component_interface_function)
591      {
592        new_candidate = (*create_missing_component_interface_function)(component_interface->GetParent(), target_set_flags);
593      }
594
595      if (new_candidate)
596      {
597        component_interface = new_candidate;
598        parent_candidate = new_candidate;
599      }
600      else
601      {
602        std::stringstream message;
603        message << "Generic creation of port composite interface failed: No interface with relation " << make_builder::GetEnumString(static_cast<tOpCode>(opcode)) << " found below " << *component_interface->GetParent();
604        FINROC_LOG_PRINT(WARNING, message.str());
605        throw std::runtime_error(message.str());
606      }
607    }
608    assert(remaining_relations == 0);
609
610    parent = parent_candidate;
611    if (interface_modifier)
612    {
613      parent = interface_modifier->Implementation().GetComponentInterface(parent_candidate && parent_candidate->GetFlag(tFlag::INTERFACE) ? static_cast<core::tPortGroup*>(parent_candidate) : nullptr, primary_relation_id);
614    }
615  }
616
617  if (!parent)
618  {
619    relation_backend_mapping.emplace_back(primary_relation_id, nullptr);
620    return nullptr;
621  }
622
623  for (auto backend : all_backends)
624  {
625    if (backend->GetParent() == parent)
626    {
627      relation_backend_mapping.emplace_back(primary_relation_id, backend);
628      return backend;
629    }
630  }
631
632  // Create new backend below this parent
633  assert(parent != this->GetParent());
634  core::tAbstractPortCreationInfo secondary_creation_info;
635  secondary_creation_info.data_type = this->GetDataType();
636  secondary_creation_info.name = GetName();
637  secondary_creation_info.parent = parent;
638  secondary_creation_info.flags = core::tFrameworkElementFlags(tFlag::INTERFACE);
639  auto aggregator = GetAggregator(*parent, &secondary_creation_info.flags);
640  if (backend_for_client_port && aggregator->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
641  {
642    secondary_creation_info.flags.Set(tFlag::OUTPUT_PORT, backend_for_client_port);
643  }
644  all_backends.push_back(new tBackend(secondary_creation_info, *this));
645  relation_backend_mapping.emplace_back(primary_relation_id, all_backends.back());
646  return all_backends.back();
647}
648
649core::tFrameworkElementFlags tInterfaceBase::tBackend::GetDefaultPortFlags(bool generic_port_backend) const
650{
651  core::tFrameworkElementFlags result;
652  if (generic_port_backend)
653  {
654    GetAggregator(*this, &result);
655  }
656  else
657  {
658    auto aggregator = GetAggregator(*this);
659    if (aggregator && aggregator->GetFlag(tFlag::INTERFACE))
660    {
661      if (aggregator->GetFlag(tFlag::PROXY_INTERFACE))
662      {
663        result |= (tFlag::ACCEPTS_DATA | tFlag::EMITS_DATA | tFlag::PUSH_STRATEGY);
664      }
665      result |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags();
666    }
667    const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw();
668    result |= core::tFrameworkElementFlags(this->GetAllFlags().Raw() & cRELEVANT_FLAGS);
669  }
670  return result;
671}
672
673bool tInterfaceBase::tBackend::IsPartOfPartialInstantiation(int primary_relation_id, bool partial_instantiation_variant_primary_port_type)
674{
675  typedef internal::tPortTypeRelation tOpCode;
676  int switch_count = 0;
677  while (primary_relation_id)
678  {
679    int opcode = primary_relation_id & 0xFF;
680    switch_count += ((opcode == tOpCode::ePTR_COUNTER_PART || opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT) ? 1 : 0);
681    primary_relation_id = primary_relation_id >> 8;
682  }
683  bool primary_port_type_relation_id = (switch_count % 2) == 0;
684  return primary_port_type_relation_id == partial_instantiation_variant_primary_port_type;
685}
686
687void tInterfaceBase::tBackend::OnConnect(tAbstractPort& partner, bool partner_is_destination)
688{
689  if (primary_backend.operation_on_all_elements_pending)
690  {
691    return;
692  }
693
694  tBackend& other = static_cast<tBackend&>(partner);
695  bool connect_all_backends = this->IsPrimaryBackend() && other.IsPrimaryBackend();
696
697  primary_backend.operation_on_all_elements_pending = true;
698  try
699  {
700    if (primary_backend.custom_connect_function)
701    {
702      if (partner_is_destination)
703      {
704        primary_backend.custom_connect_function(*this, other);
705      }
706      else
707      {
708        primary_backend.custom_connect_function(other, *this);
709      }
710      primary_backend.operation_on_all_elements_pending = false;
711      return;
712    }
713
714    // Connect all matching backends and ports
715    for (auto this_backend : primary_backend.relation_backend_mapping)
716    {
717      for (auto other_backend : other.primary_backend.primary_backend.relation_backend_mapping)
718      {
719        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))
720        {
721          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;
722          this_backend.second->ConnectTo(*other_backend.second, direction);
723          this_backend.second->ConnectChildPortsByName(*other_backend.second, direction);
724        }
725      }
726    }
727  }
728  catch (const std::exception& e)
729  {
730    FINROC_LOG_PRINT(WARNING, "Connecting failed: ", e);
731  }
732  primary_backend.operation_on_all_elements_pending = false;
733}
734
735void tInterfaceBase::tBackend::OnDisconnect(tAbstractPort& partner, bool partner_is_destination)
736{
737  bool& pending = primary_backend.primary_backend.operation_on_all_elements_pending;
738  tBackend& other = static_cast<tBackend&>(partner).primary_backend;
739  if (pending || other.operation_on_all_elements_pending || partner_is_destination)
740  {
741    return;
742  }
743
744  pending = true;
745  try
746  {
747    // Update other backend connection info
748    for (auto this_backend : this->primary_backend.all_backends)
749    {
750      for (auto other_backend : other.primary_backend.all_backends)
751      {
752        this_backend->DisconnectFrom(*other_backend);
753      }
754    }
755
756    // Disconnect all ports to partner backends (this should also cover cases with custom connect function)
757    for (auto backend : primary_backend.all_backends)
758    {
759      for (auto port = backend->ChildPortsBegin(); port != backend->ChildPortsEnd(); ++port)
760      {
761        for (auto partner = port->IncomingConnectionsBegin(); partner != port->IncomingConnectionsEnd(); ++partner)
762        {
763          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Source().GetParent()))
764          {
765            port->DisconnectFrom(partner->Source());
766          }
767        }
768        for (auto partner = port->OutgoingConnectionsBegin(); partner != port->OutgoingConnectionsEnd(); ++partner)
769        {
770          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Destination().GetParent()))
771          {
772            port->DisconnectFrom(partner->Destination());
773          }
774        }
775      }
776    }
777  }
778  catch (const std::exception& e)
779  {
780    FINROC_LOG_PRINT(WARNING, "Disconnecting failed: ", e);
781  }
782  pending = false;
783}
784
785void tInterfaceBase::tBackend::OnInitialization()
786{
787  bool& pending = primary_backend.operation_on_all_elements_pending;
788  if (!pending)
789  {
790    pending = true;
791    for (auto backend : primary_backend.all_backends)
792    {
793      if (backend != this)
794      {
795        backend->Init();
796      }
797    }
798    pending = false;
799  }
800}
801
802void tInterfaceBase::tBackend::OnManagedDelete()
803{
804  rrlib::thread::tLock lock1(GetStructureMutex());
805
806  if (!core::tRuntimeEnvironment::ShuttingDown())
807  {
808    bool& pending = primary_backend.operation_on_all_elements_pending;
809    if (!pending)
810    {
811      pending = true;
812      for (auto backend : primary_backend.all_backends)
813      {
814        if (backend != this)
815        {
816          backend->ManagedDelete();
817        }
818      }
819      pending = false;
820    }
821  }
822
823  tAbstractPort::OnManagedDelete();
824}
825
826tInterfaceBase::tScopedExtraConstructorParameters tInterfaceBase::tScopedExtraConstructorParameters::Get()
827{
828  static tExtraConstructorParameters parameters;
829  return tScopedExtraConstructorParameters(core::tRuntimeEnvironment::GetInstance().GetStructureMutex(), &parameters);  //
830}
831
832
833//----------------------------------------------------------------------
834// End of namespace declaration
835//----------------------------------------------------------------------
836}
837}
Note: See TracBrowser for help on using the repository browser.