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/defined_conversions.h" |
---|
46 | #include "plugins/composite_ports/tInterfaceModifier.h" |
---|
47 | #include "plugins/composite_ports/interface_types.h" |
---|
48 | #include "plugins/composite_ports/internal/tPortSelectConversionOperation.h" |
---|
49 | #include "plugins/composite_ports/utils/tPortSelector.h" |
---|
50 | |
---|
51 | //---------------------------------------------------------------------- |
---|
52 | // Debugging |
---|
53 | //---------------------------------------------------------------------- |
---|
54 | #include <cassert> |
---|
55 | |
---|
56 | //---------------------------------------------------------------------- |
---|
57 | // Namespace usage |
---|
58 | //---------------------------------------------------------------------- |
---|
59 | |
---|
60 | //---------------------------------------------------------------------- |
---|
61 | // Namespace declaration |
---|
62 | //---------------------------------------------------------------------- |
---|
63 | namespace finroc |
---|
64 | { |
---|
65 | namespace composite_ports |
---|
66 | { |
---|
67 | |
---|
68 | //---------------------------------------------------------------------- |
---|
69 | // Forward declarations / typedefs / enums |
---|
70 | //---------------------------------------------------------------------- |
---|
71 | typedef core::tFrameworkElementFlag tFlag; |
---|
72 | |
---|
73 | //---------------------------------------------------------------------- |
---|
74 | // Const values |
---|
75 | //---------------------------------------------------------------------- |
---|
76 | const std::string cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION = "finroc.composite_ports.single_backend_instantiation"; |
---|
77 | |
---|
78 | //---------------------------------------------------------------------- |
---|
79 | // Implementation |
---|
80 | //---------------------------------------------------------------------- |
---|
81 | |
---|
82 | namespace |
---|
83 | { |
---|
84 | |
---|
85 | const tInterfaceModifier::tImplementation cMODIFIER_DEFAULT_IMPLEMENTATION; |
---|
86 | |
---|
87 | const core::tFrameworkElement* GetAggregator(const core::tFrameworkElement& element, core::tFrameworkElementFlags* extend_with_default_ports_flags = nullptr) |
---|
88 | { |
---|
89 | if (element.GetFlag(tFlag::EDGE_AGGREGATOR) && (!element.IsPort())) |
---|
90 | { |
---|
91 | if (element.GetFlag(tFlag::INTERFACE) && extend_with_default_ports_flags) |
---|
92 | { |
---|
93 | (*extend_with_default_ports_flags) |= static_cast<const core::tPortGroup&>(element).GetDefaultPortFlags(); |
---|
94 | if (element.GetFlag(tFlag::SENSOR_DATA)) |
---|
95 | { |
---|
96 | (*extend_with_default_ports_flags) |= tFlag::SENSOR_DATA; |
---|
97 | } |
---|
98 | if (element.GetFlag(tFlag::CONTROLLER_DATA)) |
---|
99 | { |
---|
100 | (*extend_with_default_ports_flags) |= tFlag::CONTROLLER_DATA; |
---|
101 | } |
---|
102 | if (element.GetFlag(tFlag::INTERFACE_FOR_INPUTS) || element.GetFlag(tFlag::PARAMETER_INTERFACE)) |
---|
103 | { |
---|
104 | (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_INPUT_PORT_FLAGS; |
---|
105 | } |
---|
106 | if (element.GetFlag(tFlag::INTERFACE_FOR_OUTPUTS)) |
---|
107 | { |
---|
108 | (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_OUTPUT_PORT_FLAGS; |
---|
109 | } |
---|
110 | if (element.GetFlag(tFlag::PROXY_INTERFACE)) |
---|
111 | { |
---|
112 | (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA; |
---|
113 | } |
---|
114 | if (element.GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS)) |
---|
115 | { |
---|
116 | (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA; |
---|
117 | } |
---|
118 | } |
---|
119 | return &element; |
---|
120 | } |
---|
121 | return element.GetParent() ? GetAggregator(*element.GetParent(), extend_with_default_ports_flags) : nullptr; |
---|
122 | } |
---|
123 | |
---|
124 | tInterfaceModifier* GetModifier(const core::tFrameworkElement& any_element) |
---|
125 | { |
---|
126 | auto current_element = &any_element; |
---|
127 | do |
---|
128 | { |
---|
129 | auto annotation = current_element->GetAnnotation<tInterfaceModifier>(); |
---|
130 | if (annotation) |
---|
131 | { |
---|
132 | return annotation; |
---|
133 | } |
---|
134 | current_element = current_element->GetParent(); |
---|
135 | } |
---|
136 | while (current_element); |
---|
137 | return nullptr; |
---|
138 | } |
---|
139 | |
---|
140 | tInterfaceBase::tPrimaryPortType ModifierDefinesPartialInterface(const core::tFrameworkElement& parent, const rrlib::rtti::tType& interface_type) |
---|
141 | { |
---|
142 | tInterfaceModifier* modifier = GetModifier(parent); |
---|
143 | if (modifier) |
---|
144 | { |
---|
145 | return modifier->Implementation().PartialInterface(interface_type); |
---|
146 | } |
---|
147 | return tInterfaceBase::tPrimaryPortType::ANY; |
---|
148 | } |
---|
149 | |
---|
150 | core::tAbstractPortCreationInfo MakeCreationInfo(const rrlib::rtti::tType& interface_type, const std::string& name, core::tFrameworkElement& parent_interface, bool partial_interface, bool shared) |
---|
151 | { |
---|
152 | core::tAbstractPortCreationInfo result; |
---|
153 | result.data_type = interface_type; |
---|
154 | if (partial_interface) |
---|
155 | { |
---|
156 | auto partial_type = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo()).GetPartialType(); |
---|
157 | result.data_type = partial_type ? partial_type : result.data_type; |
---|
158 | } |
---|
159 | result.parent = &parent_interface; |
---|
160 | result.flags |= tFlag::INTERFACE; |
---|
161 | GetAggregator(parent_interface, &result.flags); |
---|
162 | result.name = name; |
---|
163 | assert(result.flags.Get(tFlag::EMITS_DATA) || result.flags.Get(tFlag::ACCEPTS_DATA)); |
---|
164 | if (shared) |
---|
165 | { |
---|
166 | result.flags |= tFlag::SHARED_PORT; |
---|
167 | } |
---|
168 | return result; |
---|
169 | } |
---|
170 | |
---|
171 | void FindInterfacesBelowImplementation(std::vector<tInterfaceBase>& result, core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces) |
---|
172 | { |
---|
173 | for (auto it = parent.ChildrenBegin(); it != parent.ChildrenEnd(); ++it) |
---|
174 | { |
---|
175 | bool is_backend = typeid(*it) == typeid(tInterfaceBase::tBackend); |
---|
176 | if (is_backend) |
---|
177 | { |
---|
178 | tInterfaceBase::tBackend& candidate = static_cast<tInterfaceBase::tBackend&>(*it); |
---|
179 | if (candidate.IsPrimaryBackend() && (candidate.GetDataType() == type || ((!skip_derived_interfaces) && rrlib::rtti::conversion::tStaticCastOperation::IsImplicitlyConvertibleTo(candidate.GetDataType(), type)))) |
---|
180 | { |
---|
181 | result.emplace_back(&candidate); |
---|
182 | continue; |
---|
183 | } |
---|
184 | } |
---|
185 | if ((!it->IsPort()) || is_backend) |
---|
186 | { |
---|
187 | FindInterfacesBelowImplementation(result, *it, type, skip_derived_interfaces); |
---|
188 | } |
---|
189 | } |
---|
190 | } |
---|
191 | |
---|
192 | //! Connector with operations for custom connecting attached |
---|
193 | const core::tConnectionFlags cRETAIN_FLAGS_FOR_CHILD_CONNECTIONS = core::tConnectionFlag::SCHEDULING_NEUTRAL | core::tConnectionFlag::DIRECTION_TO_SOURCE | core::tConnectionFlag::DIRECTION_TO_DESTINATION; |
---|
194 | |
---|
195 | class tConversionConnector : public core::tConnector |
---|
196 | { |
---|
197 | |
---|
198 | //---------------------------------------------------------------------- |
---|
199 | // Public methods and typedefs |
---|
200 | //---------------------------------------------------------------------- |
---|
201 | public: |
---|
202 | |
---|
203 | tConversionConnector(core::tAbstractPort& source_port, core::tAbstractPort& destination_port, const core::tConnectOptions& connect_options) : |
---|
204 | tConnector(source_port, destination_port, connect_options, this->connect_options.conversion_operations), |
---|
205 | connect_options(connect_options), |
---|
206 | original_flags(connect_options.flags.Raw() & cRETAIN_FLAGS_FOR_CHILD_CONNECTIONS.Raw()) |
---|
207 | {} |
---|
208 | |
---|
209 | const core::tConnectOptions& ChildConnectOptions() const |
---|
210 | { |
---|
211 | connect_options.flags = original_flags; |
---|
212 | return connect_options; |
---|
213 | } |
---|
214 | |
---|
215 | const core::tConnectOptions& ChildConnectOptions(const core::tConnectionFlag direction_flag) const |
---|
216 | { |
---|
217 | connect_options.flags = original_flags; |
---|
218 | connect_options.flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, direction_flag == core::tConnectionFlag::DIRECTION_TO_SOURCE); |
---|
219 | connect_options.flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, direction_flag == core::tConnectionFlag::DIRECTION_TO_DESTINATION); |
---|
220 | return connect_options; |
---|
221 | } |
---|
222 | |
---|
223 | //---------------------------------------------------------------------- |
---|
224 | // Private fields and methods |
---|
225 | //---------------------------------------------------------------------- |
---|
226 | private: |
---|
227 | |
---|
228 | /*! |
---|
229 | * Applied connect operations |
---|
230 | * Notably, the flags are only accessed within this file (with runtime structure lock). |
---|
231 | * Therefore, they can be temporarily modified (avoiding all the overhead for copying options) |
---|
232 | */ |
---|
233 | mutable core::tConnectOptions connect_options; |
---|
234 | const core::tConnectionFlags original_flags; |
---|
235 | |
---|
236 | }; |
---|
237 | |
---|
238 | bool CompiledConnectOptions(const rrlib::rtti::conversion::tConversionOperationSequence& options) |
---|
239 | { |
---|
240 | bool raw = (options.Size() >= 1 && ((!options[0].second) || (options[0].second->Parameter() && options.GetParameterValue(0).GetType() != options[0].second->Parameter().GetType()))) || |
---|
241 | (options.Size() >= 2 && ((!options[1].second) || (options[1].second->Parameter() && options.GetParameterValue(1).GetType() != options[1].second->Parameter().GetType()))); |
---|
242 | return !raw; |
---|
243 | } |
---|
244 | |
---|
245 | } |
---|
246 | |
---|
247 | void tInterfaceBase::operator()(core::tAbstractPortCreationInfo& creation_info) const |
---|
248 | { |
---|
249 | if ((!Backend()) || (Backend() && Backend()->convenience_port_type)) |
---|
250 | { |
---|
251 | creation_info.flags |= tFlag::READY; // tComponent::cNO_PORT_NAME_BUILDER; |
---|
252 | } |
---|
253 | if (!Backend()) |
---|
254 | { |
---|
255 | creation_info.flags |= tFlag::DELETED; |
---|
256 | return; |
---|
257 | } |
---|
258 | |
---|
259 | creation_info.parent = &Backend()->primary_backend; |
---|
260 | |
---|
261 | auto aggregator = GetAggregator(*creation_info.parent); |
---|
262 | if (aggregator && aggregator->GetFlag(tFlag::INTERFACE)) |
---|
263 | { |
---|
264 | creation_info.flags |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags(); |
---|
265 | } |
---|
266 | const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw(); |
---|
267 | creation_info.flags |= core::tFrameworkElementFlags(creation_info.parent->GetAllFlags().Raw() & cRELEVANT_FLAGS); |
---|
268 | |
---|
269 | if (Backend()->primary_backend.IsPartialInterface() && Backend()->primary_backend.PrimaryPortType() != tPrimaryPortType::ANY && Backend()->primary_backend.relation_backend_mapping.front().second == nullptr) |
---|
270 | { |
---|
271 | creation_info.flags |= tFlag::DELETED; |
---|
272 | } |
---|
273 | else if (creation_info.parent) |
---|
274 | { |
---|
275 | auto modifier = GetModifier(*creation_info.parent); |
---|
276 | if (modifier) |
---|
277 | { |
---|
278 | modifier->Implementation().AdjustPortCreationInfo(creation_info); |
---|
279 | } |
---|
280 | } |
---|
281 | |
---|
282 | return; |
---|
283 | } |
---|
284 | |
---|
285 | core::tConnector* tInterfaceBase::ConnectTo(const tInterfaceBase& partner, const core::tConnectOptions& connect_options) |
---|
286 | { |
---|
287 | if (Backend() && partner.Backend()) |
---|
288 | { |
---|
289 | for (auto this_backend : Backend()->relation_backend_mapping) |
---|
290 | { |
---|
291 | for (auto other_backend : partner.Backend()->primary_backend.relation_backend_mapping) |
---|
292 | { |
---|
293 | if (this_backend.second && other_backend.second && this_backend.first - Backend()->primary_relation_id == other_backend.first - partner.Backend()->primary_relation_id) |
---|
294 | { |
---|
295 | return this_backend.second->ConnectTo(*other_backend.second, connect_options); |
---|
296 | } |
---|
297 | } |
---|
298 | } |
---|
299 | } |
---|
300 | return nullptr; |
---|
301 | } |
---|
302 | |
---|
303 | tInterfaceBase::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) |
---|
304 | { |
---|
305 | assert(parent); |
---|
306 | if (parent->Backend() == nullptr) |
---|
307 | { |
---|
308 | return nullptr; |
---|
309 | } |
---|
310 | tBackend* parent_backend = parent->Backend()->GetBackend(primary_relation_id); |
---|
311 | bool partial_interface = false; |
---|
312 | assert(parent_backend || parent->Backend()->IsPartialInterface()); |
---|
313 | if (!parent_backend) |
---|
314 | { |
---|
315 | const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo()); |
---|
316 | interface_type = info.GetPartialType(); |
---|
317 | partial_interface = interface_type && primary_port_type != tPrimaryPortType::ANY; |
---|
318 | if (partial_interface) |
---|
319 | { |
---|
320 | parent_backend = parent->Backend(); |
---|
321 | } |
---|
322 | } |
---|
323 | 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; |
---|
324 | } |
---|
325 | |
---|
326 | tInterfaceBase::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) |
---|
327 | { |
---|
328 | const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo()); |
---|
329 | 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; |
---|
330 | } |
---|
331 | |
---|
332 | void tInterfaceBase::SetConfigEntry(const rrlib::uri::tPath& config_entry) |
---|
333 | { |
---|
334 | uint interface_count = 0; |
---|
335 | auto primary_backend = this->Backend(); |
---|
336 | if (primary_backend) |
---|
337 | { |
---|
338 | for (auto backend : primary_backend->primary_backend.all_backends) |
---|
339 | { |
---|
340 | auto aggregator = GetAggregator(*backend); |
---|
341 | if (aggregator && (!aggregator->IsPort()) && aggregator->GetFlag(tFlag::INTERFACE) && aggregator->GetFlag(tFlag::PARAMETER_INTERFACE)) |
---|
342 | { |
---|
343 | auto parameter_info = backend->GetAnnotation<parameters::internal::tParameterInfo>(); |
---|
344 | if (!parameter_info) |
---|
345 | { |
---|
346 | parameter_info = &backend->EmplaceAnnotation<parameters::internal::tParameterInfo>(); |
---|
347 | } |
---|
348 | std::stringstream temp; // Temporary solution until tParameterInfo class accepts paths |
---|
349 | temp << config_entry; |
---|
350 | parameter_info->SetConfigEntry(temp.str(), false); |
---|
351 | interface_count++; |
---|
352 | } |
---|
353 | } |
---|
354 | if (!interface_count) |
---|
355 | { |
---|
356 | FINROC_LOG_PRINT(WARNING, "No parameters backend in interface ", *primary_backend); |
---|
357 | } |
---|
358 | } |
---|
359 | else |
---|
360 | { |
---|
361 | FINROC_LOG_PRINT(WARNING, "Called on empty interface wrapper"); |
---|
362 | } |
---|
363 | } |
---|
364 | |
---|
365 | |
---|
366 | tInterfaceBase::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) : |
---|
367 | tAbstractPort(MakeCreationInfo(interface_type, name, *parent, partial_interface || tScopedExtraConstructorParameters::Get()->partial_interface || ModifierDefinesPartialInterface(*parent, interface_type), tScopedExtraConstructorParameters::Get()->shared)), |
---|
368 | parent_component(parent_component), |
---|
369 | primary_backend(*this), |
---|
370 | custom_connect_function(custom_connect_function), |
---|
371 | convenience_port_type(convenience_port_type), |
---|
372 | primary_relation_id(primary_relation_id), |
---|
373 | create_missing_component_interface_function(create_missing_component_interface_function), |
---|
374 | primary_port_type(primary_port_type), |
---|
375 | partial_interface(static_cast<const internal::tInterfaceTypeInfo&>(GetDataType().SharedTypeInfo()).GetFullType() != GetDataType()), |
---|
376 | partial_interface_primary_port_type(true) |
---|
377 | { |
---|
378 | all_backends.emplace_back(this); |
---|
379 | tBackend* primary_relation_backend = this; |
---|
380 | if (this->partial_interface && primary_port_type != tPrimaryPortType::ANY) |
---|
381 | { |
---|
382 | auto aggregator = GetAggregator(*this); |
---|
383 | auto partial_definition = ModifierDefinesPartialInterface(*aggregator, interface_type); |
---|
384 | if (partial_definition != tPrimaryPortType::ANY) |
---|
385 | { |
---|
386 | this->partial_interface_primary_port_type = partial_definition == primary_port_type; |
---|
387 | } |
---|
388 | else |
---|
389 | { |
---|
390 | bool sensor_parent = (aggregator && (aggregator->GetFlag(tFlag::SENSOR_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::SENSOR_PORT)); |
---|
391 | bool controller_parent = (aggregator && (aggregator->GetFlag(tFlag::CONTROLLER_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::CONTROLLER_PORT)); |
---|
392 | if ((sensor_parent && primary_port_type == tPrimaryPortType::CONTROLLER_PORT) || (controller_parent && primary_port_type == tPrimaryPortType::SENSOR_PORT)) |
---|
393 | { |
---|
394 | this->partial_interface_primary_port_type = false; |
---|
395 | } |
---|
396 | } |
---|
397 | if (!this->partial_interface_primary_port_type) |
---|
398 | { |
---|
399 | primary_relation_backend = nullptr; |
---|
400 | } |
---|
401 | } |
---|
402 | relation_backend_mapping.emplace_back(primary_relation_id, primary_relation_backend); |
---|
403 | } |
---|
404 | |
---|
405 | tInterfaceBase::tBackend::tBackend(core::tAbstractPortCreationInfo& creation_info, tBackend& primary) : |
---|
406 | tAbstractPort(creation_info), |
---|
407 | parent_component(primary.parent_component), |
---|
408 | primary_backend(primary), |
---|
409 | custom_connect_function(primary.custom_connect_function), |
---|
410 | convenience_port_type(false), |
---|
411 | primary_relation_id(primary.primary_relation_id), |
---|
412 | create_missing_component_interface_function(nullptr), |
---|
413 | primary_port_type(primary.primary_port_type), |
---|
414 | partial_interface(primary.partial_interface), |
---|
415 | partial_interface_primary_port_type(primary.partial_interface_primary_port_type) |
---|
416 | { |
---|
417 | } |
---|
418 | |
---|
419 | void tInterfaceBase::tBackend::ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options) |
---|
420 | { |
---|
421 | if (!CompiledConnectOptions(connect_options.conversion_operations)) |
---|
422 | { |
---|
423 | throw std::runtime_error("This function requires compiled connect options"); |
---|
424 | } |
---|
425 | |
---|
426 | struct tPerSelectOperation |
---|
427 | { |
---|
428 | const internal::tPortSelectConversionOperation* operation = nullptr; |
---|
429 | const utils::tPortSelector* selector = nullptr; |
---|
430 | } select_operations[2]; |
---|
431 | size_t select_operation_count = 0; |
---|
432 | bool nested_connect_options_differ = false; |
---|
433 | |
---|
434 | struct tNestedOperation |
---|
435 | { |
---|
436 | const rrlib::rtti::conversion::tRegisteredConversionOperation* operation = nullptr; |
---|
437 | size_t index = 0; |
---|
438 | }; |
---|
439 | struct tNestedOperations |
---|
440 | { |
---|
441 | tNestedOperation operations[2]; |
---|
442 | size_t count = 0; |
---|
443 | |
---|
444 | void Add(const tNestedOperation& op) |
---|
445 | { |
---|
446 | operations[count] = op; |
---|
447 | count++; |
---|
448 | } |
---|
449 | |
---|
450 | } nested_operations_non_convertible, nested_operations_convertible; |
---|
451 | |
---|
452 | for (size_t i = 0; i < connect_options.conversion_operations.Size(); i++) |
---|
453 | { |
---|
454 | tNestedOperation nested_operation; |
---|
455 | nested_operation.operation = connect_options.conversion_operations[i].second; |
---|
456 | nested_operation.index = i; |
---|
457 | bool nested_operation_valid = true; |
---|
458 | if (typeid(*connect_options.conversion_operations[i].second) == typeid(internal::tPortSelectConversionOperation)) |
---|
459 | { |
---|
460 | tPerSelectOperation data; |
---|
461 | data.operation = static_cast<const internal::tPortSelectConversionOperation*>(connect_options.conversion_operations[i].second); |
---|
462 | data.selector = connect_options.conversion_operations.GetParameterValue(i).Get<utils::tPortSelector>(); |
---|
463 | select_operations[select_operation_count] = data; |
---|
464 | select_operation_count++; |
---|
465 | |
---|
466 | nested_connect_options_differ = data.operation->NestedVariant() != data.operation; |
---|
467 | nested_operation_valid = data.operation->NestedVariant(); |
---|
468 | } |
---|
469 | if (nested_operation_valid) |
---|
470 | { |
---|
471 | nested_operations_non_convertible.Add(nested_operation); |
---|
472 | if (connect_options.conversion_operations[i].second != &cCONNECT_BY_NAME_OPERATION) |
---|
473 | { |
---|
474 | nested_operations_convertible.Add(nested_operation); |
---|
475 | } |
---|
476 | } |
---|
477 | } |
---|
478 | |
---|
479 | for (auto port = this->ChildPortsBegin(); port != this->ChildPortsEnd(); ++port) |
---|
480 | { |
---|
481 | auto other_port_element = destination.GetChild(port->GetName()); |
---|
482 | if (other_port_element && other_port_element->IsPort()) |
---|
483 | { |
---|
484 | auto& other_port = static_cast<core::tAbstractPort&>(*other_port_element); |
---|
485 | |
---|
486 | // Check whether to include port |
---|
487 | bool skip = false; |
---|
488 | for (size_t i = 0; i < select_operation_count; i++) |
---|
489 | { |
---|
490 | const tPerSelectOperation& data = select_operations[i]; |
---|
491 | if (!data.operation->NestedOnly()) |
---|
492 | { |
---|
493 | if (data.operation->ExcludeOperation()) |
---|
494 | { |
---|
495 | skip |= data.selector->Accepts(*port) || data.selector->Accepts(other_port); |
---|
496 | } |
---|
497 | else |
---|
498 | { |
---|
499 | skip |= (!data.selector->Accepts(*port)) && (!data.selector->Accepts(other_port)); |
---|
500 | } |
---|
501 | } |
---|
502 | } |
---|
503 | if (skip) |
---|
504 | { |
---|
505 | continue; |
---|
506 | } |
---|
507 | |
---|
508 | |
---|
509 | if (port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE) |
---|
510 | { |
---|
511 | auto option_flags = connect_options.flags; |
---|
512 | option_flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, false); |
---|
513 | option_flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, false); |
---|
514 | port->ConnectTo(other_port, option_flags); |
---|
515 | } |
---|
516 | else |
---|
517 | { |
---|
518 | if (IsInterfaceType(port->GetDataType())) |
---|
519 | { |
---|
520 | bool convertible = port->GetDataType() == other_port.GetDataType() || IsDerivedFrom(port->GetDataType(), other_port.GetDataType()) || IsDerivedFrom(other_port.GetDataType(), port->GetDataType()); |
---|
521 | const tNestedOperations& operations = convertible ? nested_operations_convertible : nested_operations_non_convertible; |
---|
522 | if ((!nested_connect_options_differ) && operations.count == connect_options.conversion_operations.Size()) |
---|
523 | { |
---|
524 | port->ConnectTo(other_port, connect_options); |
---|
525 | } |
---|
526 | else |
---|
527 | { |
---|
528 | core::tConnectOptions nested_options(connect_options.flags); |
---|
529 | if (operations.count) |
---|
530 | { |
---|
531 | nested_options.conversion_operations = operations.count == 1 ? rrlib::rtti::conversion::tConversionOperationSequence(*operations.operations[0].operation) : rrlib::rtti::conversion::tConversionOperationSequence(*operations.operations[0].operation, *operations.operations[1].operation); |
---|
532 | } |
---|
533 | for (size_t i = 0; i < operations.count; i++) |
---|
534 | { |
---|
535 | if (nested_options.conversion_operations[i].second->Parameter() && connect_options.conversion_operations.GetParameterValue(operations.operations[i].index)) |
---|
536 | { |
---|
537 | nested_options.conversion_operations.SetParameterValue(i, connect_options.conversion_operations.GetParameterValue(operations.operations[i].index)); |
---|
538 | } |
---|
539 | } |
---|
540 | port->ConnectTo(other_port, nested_options); |
---|
541 | } |
---|
542 | } |
---|
543 | else |
---|
544 | { |
---|
545 | port->ConnectTo(other_port, connect_options.flags); |
---|
546 | } |
---|
547 | } |
---|
548 | } |
---|
549 | } |
---|
550 | } |
---|
551 | |
---|
552 | core::tConnector* tInterfaceBase::tBackend::CreateConnector(core::tAbstractPort& destination, const core::tConnectOptions& connect_options) |
---|
553 | { |
---|
554 | if (!(CompiledConnectOptions(connect_options.conversion_operations))) |
---|
555 | { |
---|
556 | assert(connect_options.conversion_operations.Size() >= 1); |
---|
557 | const rrlib::rtti::conversion::tRegisteredConversionOperation* operations[2] = { nullptr, nullptr }; |
---|
558 | |
---|
559 | // Resolve ambiguous operations |
---|
560 | for (size_t i = 0; i < connect_options.conversion_operations.Size(); i++) |
---|
561 | { |
---|
562 | auto operation = connect_options.conversion_operations[i]; |
---|
563 | if (operation.second) |
---|
564 | { |
---|
565 | operations[i] = operation.second; |
---|
566 | } |
---|
567 | else |
---|
568 | { |
---|
569 | auto& registered_operations = rrlib::rtti::conversion::tRegisteredConversionOperation::GetRegisteredOperations(); |
---|
570 | for (auto it = registered_operations.operations.Begin(); it != registered_operations.operations.End(); ++it) |
---|
571 | { |
---|
572 | if (strcmp((*it)->Name(), operation.first) == 0) |
---|
573 | { |
---|
574 | operations[i] = *it; |
---|
575 | break; |
---|
576 | } |
---|
577 | } |
---|
578 | } |
---|
579 | |
---|
580 | if (!operations[i]) |
---|
581 | { |
---|
582 | throw std::runtime_error(std::string("Operation lookup failed: ") + operation.first); |
---|
583 | } |
---|
584 | } |
---|
585 | |
---|
586 | rrlib::rtti::conversion::tConversionOperationSequence conversion = connect_options.conversion_operations.Size() == 1 ? rrlib::rtti::conversion::tConversionOperationSequence(*operations[0]) : rrlib::rtti::conversion::tConversionOperationSequence(*operations[0], *operations[1], connect_options.conversion_operations.IntermediateType() ? connect_options.conversion_operations.IntermediateType() : destination.GetDataType()); |
---|
587 | |
---|
588 | // ############ |
---|
589 | // Convert any parameters provided as strings to their required types (see tConversionOperationSequence.cpp) |
---|
590 | // ############ |
---|
591 | for (size_t i = 0; i < 2; i++) |
---|
592 | { |
---|
593 | const rrlib::rtti::conversion::tRegisteredConversionOperation* operation = operations[i]; |
---|
594 | if (operation && operation->Parameter() && connect_options.conversion_operations.GetParameterValue(i)) |
---|
595 | { |
---|
596 | const rrlib::rtti::tTypedConstPointer& value = connect_options.conversion_operations.GetParameterValue(i); |
---|
597 | if (value.GetType() == operation->Parameter().GetType()) |
---|
598 | { |
---|
599 | conversion.SetParameterValue(i, value); |
---|
600 | } |
---|
601 | else if (value.GetType() == rrlib::rtti::tDataType<std::string>()) |
---|
602 | { |
---|
603 | rrlib::serialization::tStringInputStream stream(*value.Get<std::string>()); |
---|
604 | auto buffer = operation->Parameter().GetType().CreateGenericObject(); |
---|
605 | buffer->Deserialize(stream); |
---|
606 | conversion.SetParameterValue(i, *buffer); |
---|
607 | } |
---|
608 | else |
---|
609 | { |
---|
610 | throw std::runtime_error(std::string("Parameter ") + operation->Parameter().GetName() + " has invalid type"); |
---|
611 | } |
---|
612 | } |
---|
613 | } |
---|
614 | |
---|
615 | return new tConversionConnector(*this, destination, core::tConnectOptions(conversion, connect_options.flags)); |
---|
616 | } |
---|
617 | return new tConversionConnector(*this, destination, connect_options); |
---|
618 | } |
---|
619 | |
---|
620 | bool tInterfaceBase::tBackend::CreateOutputPort(int primary_relation_id) |
---|
621 | { |
---|
622 | auto backend = GetBackend(primary_relation_id); |
---|
623 | if (!backend) |
---|
624 | { |
---|
625 | return false; |
---|
626 | } |
---|
627 | auto component_interface = GetAggregator(*backend); |
---|
628 | if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent()))) |
---|
629 | { |
---|
630 | return false; |
---|
631 | } |
---|
632 | if (component_interface->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS)) |
---|
633 | { |
---|
634 | int last_relation = primary_relation_id & 0xFF; |
---|
635 | bool derived_from_backend_is_output = CreateOutputPort(primary_relation_id >> 8); |
---|
636 | if (last_relation == internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT) |
---|
637 | { |
---|
638 | return !derived_from_backend_is_output; |
---|
639 | } |
---|
640 | else if (last_relation == internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT) |
---|
641 | { |
---|
642 | return derived_from_backend_is_output; |
---|
643 | } |
---|
644 | } |
---|
645 | if (component_interface->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS)) |
---|
646 | { |
---|
647 | return true; |
---|
648 | } |
---|
649 | if (component_interface->GetFlag(tFlag::INTERFACE_FOR_INPUTS) || component_interface->GetFlag(tFlag::PARAMETER_INTERFACE)) |
---|
650 | { |
---|
651 | return false; |
---|
652 | } |
---|
653 | throw std::runtime_error("Unspecified port direction"); |
---|
654 | } |
---|
655 | |
---|
656 | core::tAbstractPort* tInterfaceBase::tBackend::CreatePort(const core::tAbstractPortCreationInfo& creation_info, int primary_relation_id) const |
---|
657 | { |
---|
658 | auto modifier = GetModifier(*creation_info.parent); |
---|
659 | return (modifier ? modifier->Implementation() : cMODIFIER_DEFAULT_IMPLEMENTATION).CreatePort(creation_info, primary_relation_id); |
---|
660 | } |
---|
661 | |
---|
662 | std::vector<tInterfaceBase> tInterfaceBase::FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces) |
---|
663 | { |
---|
664 | std::vector<tInterfaceBase> result; |
---|
665 | if (type.GetTypeClassification() == rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE) |
---|
666 | { |
---|
667 | FindInterfacesBelowImplementation(result, parent, type, skip_derived_interfaces); |
---|
668 | } |
---|
669 | return result; |
---|
670 | } |
---|
671 | |
---|
672 | tInterfaceBase::tBackend* tInterfaceBase::tBackend::GetBackend(int primary_relation_id) |
---|
673 | { |
---|
674 | if (&primary_backend != this) |
---|
675 | { |
---|
676 | return primary_backend.GetBackend(primary_relation_id); |
---|
677 | } |
---|
678 | |
---|
679 | for (auto & entry : relation_backend_mapping) |
---|
680 | { |
---|
681 | if (entry.first == primary_relation_id) |
---|
682 | { |
---|
683 | return entry.second; |
---|
684 | } |
---|
685 | } |
---|
686 | |
---|
687 | core::tFrameworkElement* parent = nullptr; |
---|
688 | bool do_not_create_primary_port_type = relation_backend_mapping.front().second == nullptr; |
---|
689 | bool partial_interface_direction_is_output = GetAggregator(*this)->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS); |
---|
690 | bool partial_interface_primary_relation_direction_is_output = !partial_interface_direction_is_output; |
---|
691 | bool backend_for_client_port = false; |
---|
692 | if (GetParent() && typeid(*GetParent()).name() == typeid(tBackend).name()) |
---|
693 | { |
---|
694 | parent = static_cast<tBackend&>(*GetParent()).GetBackend(primary_relation_id); |
---|
695 | } |
---|
696 | else if (core::tFrameworkElementTags::IsTagged(*this->GetParent(), cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION)) |
---|
697 | { |
---|
698 | parent = this->GetParent(); |
---|
699 | } |
---|
700 | else if (this->partial_interface && (!IsPartOfPartialInstantiation(primary_relation_id, this->partial_interface_primary_port_type))) |
---|
701 | { |
---|
702 | parent = nullptr; // Skip |
---|
703 | } |
---|
704 | else |
---|
705 | { |
---|
706 | // Actually process relation |
---|
707 | std::vector<int> relation_list; |
---|
708 | tFrameworkElement* component_interface = this->GetParent(); |
---|
709 | int relation_id = primary_relation_id; |
---|
710 | if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent()))) |
---|
711 | { |
---|
712 | FINROC_LOG_PRINT(WARNING, "Generic creation of port composite interfaces with multiple port types only works on components"); |
---|
713 | throw std::runtime_error("Generic creation of port composite interfaces with multiple port types only works on components"); |
---|
714 | } |
---|
715 | |
---|
716 | 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; |
---|
717 | tInterfaceModifier* interface_modifier = GetModifier(*component_interface); |
---|
718 | |
---|
719 | // Compute opcode sequence |
---|
720 | { |
---|
721 | while (relation_id) |
---|
722 | { |
---|
723 | int opcode = relation_id & 0xFF; |
---|
724 | relation_list.push_back(opcode); |
---|
725 | relation_id = relation_id >> 8; |
---|
726 | } |
---|
727 | std::reverse(relation_list.begin(), relation_list.end()); |
---|
728 | } |
---|
729 | |
---|
730 | tFrameworkElement* parent_candidate = do_not_create_primary_port_type ? nullptr : component_interface; |
---|
731 | core::tFrameworkElementFlags use_these_original_flags; |
---|
732 | if (do_not_create_primary_port_type) |
---|
733 | { |
---|
734 | assert(partial_interface && primary_port_type != tPrimaryPortType::ANY); |
---|
735 | 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); |
---|
736 | use_these_original_flags.Set(tFlag::PROXY_INTERFACE, component_interface->GetFlag(tFlag::PROXY_INTERFACE)); |
---|
737 | } |
---|
738 | |
---|
739 | int remaining_relations = relation_list.size(); |
---|
740 | for (int opcode : relation_list) |
---|
741 | { |
---|
742 | remaining_relations--; |
---|
743 | core::tFrameworkElementFlags original_flags = use_these_original_flags.Raw() ? use_these_original_flags : parent_candidate->GetAllFlags(); |
---|
744 | use_these_original_flags = core::tFrameworkElementFlags(); |
---|
745 | core::tFrameworkElementFlags target_set_flags = core::tFrameworkElementFlags(original_flags.Raw() & relevant_flags.Raw()); |
---|
746 | core::tFrameworkElementFlags target_unset_flags = core::tFrameworkElementFlags((~original_flags.Raw()) & relevant_flags.Raw()); |
---|
747 | |
---|
748 | typedef internal::tPortTypeRelation tOpCode; |
---|
749 | switch (opcode) |
---|
750 | { |
---|
751 | case tOpCode::ePTR_COUNTER_PART: |
---|
752 | case tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT: |
---|
753 | if (original_flags.Get(tFlag::CONTROLLER_DATA) && (!original_flags.Get(tFlag::SENSOR_DATA))) |
---|
754 | { |
---|
755 | target_set_flags.Set(tFlag::SENSOR_DATA); |
---|
756 | target_set_flags.Set(tFlag::CONTROLLER_DATA, false); |
---|
757 | target_unset_flags.Set(tFlag::CONTROLLER_DATA); |
---|
758 | target_unset_flags.Set(tFlag::SENSOR_DATA, false); |
---|
759 | } |
---|
760 | if (original_flags.Get(tFlag::SENSOR_DATA) && (!original_flags.Get(tFlag::CONTROLLER_DATA))) |
---|
761 | { |
---|
762 | target_set_flags.Set(tFlag::CONTROLLER_DATA); |
---|
763 | target_set_flags.Set(tFlag::SENSOR_DATA, false); |
---|
764 | target_unset_flags.Set(tFlag::SENSOR_DATA); |
---|
765 | target_unset_flags.Set(tFlag::CONTROLLER_DATA, false); |
---|
766 | } |
---|
767 | if (original_flags.Get(tFlag::INTERFACE_FOR_INPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS))) |
---|
768 | { |
---|
769 | target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS); |
---|
770 | target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false); |
---|
771 | target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false); |
---|
772 | target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS); |
---|
773 | target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false); |
---|
774 | } |
---|
775 | if (original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_INPUTS))) |
---|
776 | { |
---|
777 | if (opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT) |
---|
778 | { |
---|
779 | target_set_flags = tFlag::PARAMETER_INTERFACE; |
---|
780 | target_unset_flags = core::tFrameworkElementFlags(); |
---|
781 | } |
---|
782 | else |
---|
783 | { |
---|
784 | target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS); |
---|
785 | target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false); |
---|
786 | target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS); |
---|
787 | target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false); |
---|
788 | } |
---|
789 | } |
---|
790 | break; |
---|
791 | case internal::tPortTypeRelation::ePTR_INPUT: |
---|
792 | target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS); |
---|
793 | target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false); |
---|
794 | target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS); |
---|
795 | target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false); |
---|
796 | break; |
---|
797 | case internal::tPortTypeRelation::ePTR_OUTPUT: |
---|
798 | target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS); |
---|
799 | target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false); |
---|
800 | target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false); |
---|
801 | target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS); |
---|
802 | target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false); |
---|
803 | break; |
---|
804 | case internal::tPortTypeRelation::ePTR_PARAMETER: |
---|
805 | target_set_flags = tFlag::PARAMETER_INTERFACE; |
---|
806 | target_unset_flags = core::tFrameworkElementFlags(); |
---|
807 | break; |
---|
808 | case internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT: |
---|
809 | case internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT: |
---|
810 | 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))); |
---|
811 | target_set_flags = tFlag::INTERFACE_FOR_RPC_PORTS; |
---|
812 | 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 |
---|
813 | break; |
---|
814 | default: |
---|
815 | break; |
---|
816 | } |
---|
817 | |
---|
818 | core::tFrameworkElement* new_candidate = nullptr; |
---|
819 | size_t candidate_name_length_difference = std::numeric_limits<size_t>::max(); |
---|
820 | auto component = component_interface->GetParent(); |
---|
821 | for (auto it = component->ChildrenBegin(); it != component->ChildrenEnd(); ++it) |
---|
822 | { |
---|
823 | 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) |
---|
824 | { |
---|
825 | size_t name_length_difference = std::abs(static_cast<long>(component_interface->GetName().length()) - static_cast<long>(it->GetName().length())); |
---|
826 | if (name_length_difference < candidate_name_length_difference) |
---|
827 | { |
---|
828 | new_candidate = &*it; |
---|
829 | candidate_name_length_difference = name_length_difference; |
---|
830 | } |
---|
831 | } |
---|
832 | } |
---|
833 | |
---|
834 | if ((!new_candidate) && this->IsPartialInterface() && remaining_relations) |
---|
835 | { |
---|
836 | use_these_original_flags = target_set_flags; |
---|
837 | parent_candidate = nullptr; |
---|
838 | continue; |
---|
839 | } |
---|
840 | |
---|
841 | // Not-yet-created component interfaces - until there is a generic way to do this |
---|
842 | if ((!new_candidate) && create_missing_component_interface_function) |
---|
843 | { |
---|
844 | new_candidate = (*create_missing_component_interface_function)(component_interface->GetParent(), target_set_flags); |
---|
845 | } |
---|
846 | |
---|
847 | if ((!new_candidate) && interface_modifier) |
---|
848 | { |
---|
849 | use_these_original_flags = target_set_flags; |
---|
850 | parent_candidate = nullptr; |
---|
851 | continue; |
---|
852 | } |
---|
853 | |
---|
854 | if (new_candidate) |
---|
855 | { |
---|
856 | component_interface = new_candidate; |
---|
857 | parent_candidate = new_candidate; |
---|
858 | } |
---|
859 | else |
---|
860 | { |
---|
861 | std::stringstream message; |
---|
862 | message << "Generic creation of port composite interface failed: No interface with relation " << make_builder::GetEnumString(static_cast<tOpCode>(opcode)) << " found below " << *component_interface->GetParent(); |
---|
863 | FINROC_LOG_PRINT(WARNING, message.str()); |
---|
864 | throw std::runtime_error(message.str()); |
---|
865 | } |
---|
866 | } |
---|
867 | assert(remaining_relations == 0); |
---|
868 | |
---|
869 | parent = parent_candidate; |
---|
870 | if (interface_modifier) |
---|
871 | { |
---|
872 | parent = interface_modifier->Implementation().GetComponentInterface(parent_candidate && parent_candidate->GetFlag(tFlag::INTERFACE) ? static_cast<core::tPortGroup*>(parent_candidate) : nullptr, primary_relation_id); |
---|
873 | } |
---|
874 | } |
---|
875 | |
---|
876 | if (!parent) |
---|
877 | { |
---|
878 | relation_backend_mapping.emplace_back(primary_relation_id, nullptr); |
---|
879 | return nullptr; |
---|
880 | } |
---|
881 | |
---|
882 | for (auto backend : all_backends) |
---|
883 | { |
---|
884 | if (backend->GetParent() == parent) |
---|
885 | { |
---|
886 | relation_backend_mapping.emplace_back(primary_relation_id, backend); |
---|
887 | return backend; |
---|
888 | } |
---|
889 | } |
---|
890 | |
---|
891 | // Create new backend below this parent |
---|
892 | assert(parent != this->GetParent()); |
---|
893 | core::tAbstractPortCreationInfo secondary_creation_info; |
---|
894 | secondary_creation_info.data_type = this->GetDataType(); |
---|
895 | secondary_creation_info.name = GetName(); |
---|
896 | secondary_creation_info.parent = parent; |
---|
897 | secondary_creation_info.flags = core::tFrameworkElementFlags(tFlag::INTERFACE); |
---|
898 | auto aggregator = GetAggregator(*parent, &secondary_creation_info.flags); |
---|
899 | if (backend_for_client_port && aggregator->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS)) |
---|
900 | { |
---|
901 | secondary_creation_info.flags.Set(tFlag::OUTPUT_PORT, backend_for_client_port); |
---|
902 | } |
---|
903 | if (this->GetFlag(tFlag::SHARED)) |
---|
904 | { |
---|
905 | secondary_creation_info.flags |= tFlag::SHARED; |
---|
906 | } |
---|
907 | all_backends.push_back(new tBackend(secondary_creation_info, *this)); |
---|
908 | relation_backend_mapping.emplace_back(primary_relation_id, all_backends.back()); |
---|
909 | return all_backends.back(); |
---|
910 | } |
---|
911 | |
---|
912 | core::tFrameworkElementFlags tInterfaceBase::tBackend::GetDefaultPortFlags(bool generic_port_backend) const |
---|
913 | { |
---|
914 | core::tFrameworkElementFlags result; |
---|
915 | if (generic_port_backend) |
---|
916 | { |
---|
917 | GetAggregator(*this, &result); |
---|
918 | } |
---|
919 | else |
---|
920 | { |
---|
921 | auto aggregator = GetAggregator(*this); |
---|
922 | if (aggregator && aggregator->GetFlag(tFlag::INTERFACE)) |
---|
923 | { |
---|
924 | if (aggregator->GetFlag(tFlag::PROXY_INTERFACE)) |
---|
925 | { |
---|
926 | result |= (tFlag::ACCEPTS_DATA | tFlag::EMITS_DATA | tFlag::PUSH_STRATEGY); |
---|
927 | } |
---|
928 | result |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags(); |
---|
929 | } |
---|
930 | } |
---|
931 | const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw(); |
---|
932 | result |= core::tFrameworkElementFlags(this->GetAllFlags().Raw() & cRELEVANT_FLAGS); |
---|
933 | return result; |
---|
934 | } |
---|
935 | |
---|
936 | bool tInterfaceBase::tBackend::IsPartOfPartialInstantiation(int primary_relation_id, bool partial_instantiation_variant_primary_port_type) |
---|
937 | { |
---|
938 | typedef internal::tPortTypeRelation tOpCode; |
---|
939 | int switch_count = 0; |
---|
940 | while (primary_relation_id) |
---|
941 | { |
---|
942 | int opcode = primary_relation_id & 0xFF; |
---|
943 | switch_count += ((opcode == tOpCode::ePTR_COUNTER_PART || opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT) ? 1 : 0); |
---|
944 | primary_relation_id = primary_relation_id >> 8; |
---|
945 | } |
---|
946 | bool primary_port_type_relation_id = (switch_count % 2) == 0; |
---|
947 | return primary_port_type_relation_id == partial_instantiation_variant_primary_port_type; |
---|
948 | } |
---|
949 | |
---|
950 | void tInterfaceBase::tBackend::OnConnect(tAbstractPort& partner, bool partner_is_destination) |
---|
951 | { |
---|
952 | if (primary_backend.operation_on_all_elements_pending) |
---|
953 | { |
---|
954 | return; |
---|
955 | } |
---|
956 | |
---|
957 | tBackend& other = static_cast<tBackend&>(partner); |
---|
958 | bool connect_all_backends = this->IsPrimaryBackend() && other.IsPrimaryBackend(); |
---|
959 | |
---|
960 | // Are any conversion operations set? |
---|
961 | const tConversionConnector* conversion_connector = nullptr; |
---|
962 | { |
---|
963 | if (partner_is_destination) |
---|
964 | { |
---|
965 | for (auto it = this->OutgoingConnectionsBegin(); it != this->OutgoingConnectionsEnd(); ++it) |
---|
966 | { |
---|
967 | if (&it->Destination() == &partner && typeid(*it) == typeid(tConversionConnector)) |
---|
968 | { |
---|
969 | conversion_connector = &static_cast<const tConversionConnector&>(*it); |
---|
970 | break; |
---|
971 | } |
---|
972 | } |
---|
973 | } |
---|
974 | else |
---|
975 | { |
---|
976 | for (auto it = this->IncomingConnectionsBegin(); it != this->IncomingConnectionsEnd(); ++it) |
---|
977 | { |
---|
978 | if (&it->Source() == &partner && typeid(*it) == typeid(tConversionConnector)) |
---|
979 | { |
---|
980 | conversion_connector = &static_cast<const tConversionConnector&>(*it); |
---|
981 | break; |
---|
982 | } |
---|
983 | } |
---|
984 | } |
---|
985 | } |
---|
986 | |
---|
987 | primary_backend.operation_on_all_elements_pending = true; |
---|
988 | try |
---|
989 | { |
---|
990 | if (!conversion_connector) |
---|
991 | { |
---|
992 | throw std::runtime_error("Invalid connector type"); |
---|
993 | } |
---|
994 | |
---|
995 | if (primary_backend.custom_connect_function) |
---|
996 | { |
---|
997 | if (partner_is_destination) |
---|
998 | { |
---|
999 | primary_backend.custom_connect_function(*this, other, conversion_connector->ChildConnectOptions()); |
---|
1000 | } |
---|
1001 | else |
---|
1002 | { |
---|
1003 | primary_backend.custom_connect_function(other, *this, conversion_connector->ChildConnectOptions()); |
---|
1004 | } |
---|
1005 | primary_backend.operation_on_all_elements_pending = false; |
---|
1006 | return; |
---|
1007 | } |
---|
1008 | |
---|
1009 | // Connect all matching backends and ports |
---|
1010 | for (auto this_backend : primary_backend.relation_backend_mapping) |
---|
1011 | { |
---|
1012 | for (auto other_backend : other.primary_backend.primary_backend.relation_backend_mapping) |
---|
1013 | { |
---|
1014 | 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)) |
---|
1015 | { |
---|
1016 | 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; |
---|
1017 | this_backend.second->ConnectTo(*other_backend.second, conversion_connector->ChildConnectOptions(direction)); |
---|
1018 | this_backend.second->ConnectChildPortsByName(*other_backend.second, conversion_connector->ChildConnectOptions(direction)); |
---|
1019 | } |
---|
1020 | } |
---|
1021 | } |
---|
1022 | } |
---|
1023 | catch (const std::exception& e) |
---|
1024 | { |
---|
1025 | FINROC_LOG_PRINT(WARNING, "Connecting failed: ", e); |
---|
1026 | } |
---|
1027 | primary_backend.operation_on_all_elements_pending = false; |
---|
1028 | } |
---|
1029 | |
---|
1030 | void tInterfaceBase::tBackend::OnDisconnect(tAbstractPort& partner, bool partner_is_destination) |
---|
1031 | { |
---|
1032 | bool& pending = primary_backend.primary_backend.operation_on_all_elements_pending; |
---|
1033 | tBackend& other = static_cast<tBackend&>(partner).primary_backend; |
---|
1034 | if (pending || other.operation_on_all_elements_pending || partner_is_destination) |
---|
1035 | { |
---|
1036 | return; |
---|
1037 | } |
---|
1038 | |
---|
1039 | pending = true; |
---|
1040 | try |
---|
1041 | { |
---|
1042 | // Update other backend connection info |
---|
1043 | for (auto this_backend : this->primary_backend.all_backends) |
---|
1044 | { |
---|
1045 | for (auto other_backend : other.primary_backend.all_backends) |
---|
1046 | { |
---|
1047 | this_backend->DisconnectFrom(*other_backend); |
---|
1048 | } |
---|
1049 | } |
---|
1050 | |
---|
1051 | // Disconnect all ports to partner backends (this should also cover cases with custom connect function) |
---|
1052 | for (auto backend : primary_backend.all_backends) |
---|
1053 | { |
---|
1054 | for (auto port = backend->ChildPortsBegin(); port != backend->ChildPortsEnd(); ++port) |
---|
1055 | { |
---|
1056 | for (auto partner = port->IncomingConnectionsBegin(); partner != port->IncomingConnectionsEnd(); ++partner) |
---|
1057 | { |
---|
1058 | if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Source().GetParent())) |
---|
1059 | { |
---|
1060 | port->DisconnectFrom(partner->Source()); |
---|
1061 | } |
---|
1062 | } |
---|
1063 | for (auto partner = port->OutgoingConnectionsBegin(); partner != port->OutgoingConnectionsEnd(); ++partner) |
---|
1064 | { |
---|
1065 | if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Destination().GetParent())) |
---|
1066 | { |
---|
1067 | port->DisconnectFrom(partner->Destination()); |
---|
1068 | } |
---|
1069 | } |
---|
1070 | } |
---|
1071 | } |
---|
1072 | } |
---|
1073 | catch (const std::exception& e) |
---|
1074 | { |
---|
1075 | FINROC_LOG_PRINT(WARNING, "Disconnecting failed: ", e); |
---|
1076 | } |
---|
1077 | pending = false; |
---|
1078 | } |
---|
1079 | |
---|
1080 | void tInterfaceBase::tBackend::OnInitialization() |
---|
1081 | { |
---|
1082 | bool& pending = primary_backend.operation_on_all_elements_pending; |
---|
1083 | if (!pending) |
---|
1084 | { |
---|
1085 | pending = true; |
---|
1086 | for (auto backend : primary_backend.all_backends) |
---|
1087 | { |
---|
1088 | if (backend != this) |
---|
1089 | { |
---|
1090 | backend->Init(); |
---|
1091 | } |
---|
1092 | } |
---|
1093 | pending = false; |
---|
1094 | } |
---|
1095 | } |
---|
1096 | |
---|
1097 | void tInterfaceBase::tBackend::OnManagedDelete() |
---|
1098 | { |
---|
1099 | rrlib::thread::tLock lock1(GetStructureMutex()); |
---|
1100 | |
---|
1101 | if (!core::tRuntimeEnvironment::ShuttingDown()) |
---|
1102 | { |
---|
1103 | bool& pending = primary_backend.operation_on_all_elements_pending; |
---|
1104 | if (!pending) |
---|
1105 | { |
---|
1106 | pending = true; |
---|
1107 | for (auto backend : primary_backend.all_backends) |
---|
1108 | { |
---|
1109 | if (backend != this) |
---|
1110 | { |
---|
1111 | backend->ManagedDelete(); |
---|
1112 | } |
---|
1113 | } |
---|
1114 | pending = false; |
---|
1115 | } |
---|
1116 | } |
---|
1117 | |
---|
1118 | tAbstractPort::OnManagedDelete(); |
---|
1119 | } |
---|
1120 | |
---|
1121 | tInterfaceBase::tScopedExtraConstructorParameters tInterfaceBase::tScopedExtraConstructorParameters::Get() |
---|
1122 | { |
---|
1123 | static tExtraConstructorParameters parameters; |
---|
1124 | return tScopedExtraConstructorParameters(core::tRuntimeEnvironment::GetInstance().GetStructureMutex(), ¶meters); // |
---|
1125 | } |
---|
1126 | |
---|
1127 | void tInterfaceBase::tSecondaryPortModifier::operator()(core::tAbstractPortCreationInfo& creation_info) const |
---|
1128 | { |
---|
1129 | creation_info.name = name; |
---|
1130 | creation_info.parent = &backend; |
---|
1131 | creation_info.flags |= backend.GetDefaultPortFlags(false); |
---|
1132 | |
---|
1133 | { |
---|
1134 | auto modifier = GetModifier(backend); |
---|
1135 | if (modifier) |
---|
1136 | { |
---|
1137 | modifier->Implementation().AdjustPortCreationInfo(creation_info); |
---|
1138 | } |
---|
1139 | } |
---|
1140 | } |
---|
1141 | |
---|
1142 | //---------------------------------------------------------------------- |
---|
1143 | // End of namespace declaration |
---|
1144 | //---------------------------------------------------------------------- |
---|
1145 | } |
---|
1146 | } |
---|